Setting default dropdown selection for model in Django admin interface - python

Sorry if the title is hard to follow, I can't think of a concise way to word this.
In my Django project, I have five models, ComputingObject, Laptop, Desktop, HardDrive, and SanitizationMethod. They're linked as such:
class ComputingObject(models.Model):
#various other fields...
sanitize_method = models.ForeignKey(SanitizationMethod)
class Laptop(ComputingObject):
#laptop-related fields
class SanitizationMethod(models.Model):
description = models.CharField(max_length=100)
Desktop and HardDrive also extend ComputingObject.
So in the admin interface, when creating a new instance of any of the three ComputingObject children, sanitize_method is shown as a drop-down (select) field. In my project, there are a small handful of SanitizationMethods in the database. What I want is to have that drop-down menu default to a specific (different) choice for each of the three ComputingObject children. For instance, Desktop might default to "Remove hard drives", HardDrive would be "Degauss and destroy", etc. Is there a way to do this with django?
On the surface it seems as easy as overriding the sanitize_method field for each of the three children, and putting defualt= x in each, but django disallows overriding parent fields, so this approach won't work.
I'm stumped. Does anyone know how to do this (or if it's even possible)?

You probably want to override formfield_for_foreignkey in your child models ModelAdmins, cf https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#django.contrib.admin.ModelAdmin.formfield_for_foreignkey

Related

How can I add a changeable "subfield" to a ModelField in django?

I'm trying to create a kind of "subfield" for a CharField in django, but I'm not sure (a) if it is possible at all and (b) how to succeed if it is indeed possible.
Let's say I want a model for Tools. They would have a, e.g., a field for long_name, short_name, maybe a ForeignKey for realizing different departments. One of these tools I'd like to be a Link, the said "subfield" being a URLField with the href to the webpage.
Now, I can create multiple link entries with the associated URL, but I'd rather have only one tool called "Link" with the changing URL attached. Is this a case for ForeignKey as well? Does it make sense to have a model with only one field (well, two if you count the pkid) in it?
Or am I on a completely lost path here?
If I've understood you correctly, you want to have a number of links that can be attached to a Tool model, so instead of just having a single URLField you would have a Many-to-One relation with a Link model:
class ToolLink(models.Model):
url = models.URLField(...
class Tool(models.Model):
links = models.ForeignKey(ToolLink, ...
The problem is that you only want one particular tool to be able to hold links. Your options are to create a 'Tool' base model that then has multiple different types of tool, like 'StandardTool', 'LinkTool', etc. or to setup some logic that monitors whether the Tool has links or not (or if another tool already has links) and whether creating links is acceptable.

Edit FileField file contents from Django Admin

I have a situation where I have python scripts that are stored as files that need to be modified from the Admin panel. Currently some of my models can have scripts attached to them:
class Action(PolymorphicModel):
title = models.CharField(max_length=100)
text = BBCodeField('text', blank=True)
action_script = models.FileField(upload_to='action_scripts')
In my Admin panel I can upload a file but I have been asked to make this file editable in-place if the user has the right permissions. I've searched all over for an idiomatic way to do this, and so far I've come up with the following ideas:
Override the FileField widget to include an text edit box and save button. This seems very brute forced
Replace models.FileField with subclass of models.TextField, implement read from file, save to file, but then I lose the upload widget and data still gets stored in DB. This seems dirty because in the database all I'm storing is a filename. FileField feels like the right field type here.
Write a custom ModelForm that includes forms.TextField. Handle save to file using the save method. I'm not sure how to accomplish this because I would have to generate a filename on the fly and I don't have a primary key yet. Maybe some sort of UUID?
I'm leaning against door number 3 right now, but I've only been using Django for a week, so I'm not sure this is the right way to go, or even how to do it. Also I would need to have a custom ModelForm for every model that inherits from Action, which violates DRY.
Further complications:
Not all Actions need scripts. If the textbox is empty, the FileField can just become Null.
Action is subclassed into a handful of derived classes. The editing functionality should extend to each model's Admin panel in a scalable way, like the other fields.
This question seems generic enough that its solution would be useful for those wishing to edit HTML or CSS from the admin, etc, the same as WordPress does. Searching along those lines unfortunately brings up results to do with skinning the admin, which I'm not after. In my situation I'm trying to avoid storing python code in the database for security reasons. The Admin interface is not going to be exposed to the end users so in theory it should be safe, and I get the benefit of caching, compilation and locality (less hits to the DB).
Many thanks.

Python django admin: How can I show only items belonging to specific model in an admin page?

I'm learning django for building my website.
I learned how to create models, views, but now I have some question relative to admin interface.
So I have tis code:
from django.db import models
class AudioBook(models.Model):
titolo=models.CharField(max_length=250)
capitoli=models.ManyToManyField('Chapters')
class Chapters(models.Model):
capitolo=models.CharField(max_length=250)
Now, when I add a new audiobook I can see chapters previously added to others audiobooks. This is bad. I want only the chapters taht belong to this audiobook, so, when I add a new one, the list must be empty.
I tried some things: adding limit_choices_to = models.Q(audiobook__titolo=titolo), but it doesn't work.
In command line I can retrieve these info by adding filters on Chapters object, but I can reproduce this situation in admin interface.
Any idea? I searched on google but I didn't find anything that helps me.
Germano
For ManyToMany relationships, Django admin interface allows you to see the entire list of choices you have and then you select whichever you want to add to your AudioBook object.
It does not mean all of them belong to that audio book. The selected ones (the ones you added to you audio books) will have normally a grey background
If that interface bothers you that much, I suggest that you add AudioBook foreign key in Chapters instead of your MAnyToMany relationship:
class Chapters(models.Model):
capitolo=models.CharField(max_length=250)
audio_book = models.ForeignKey(AudioBook,on_delete=models.CASCADE)
It's more relevent in your case. You still can access the audio book's chapters as easily.

How to disallow admin to change instance in Django admin?

I have a model Order and model Invoice. The Order has
invoice = models.OneToOneField('Invoice', related_name='order', on_delete=models.CASCADE, blank=True, null=True)
Invoice object is created right after order object is created an assigned to it. Admin has to edit the invoice (price field) before customer pays.
The problem is that Django-admin allows admin to change this field too (bottom of the image), which I can't risk but I want to let the pencil icon (change attributes of the invoice).
Is it possible to do that? When I add invoice to readonly_fields in OrderAdmin, Admin can't edit those attributes like invoice.price etc.
EDIT:
So I want admin to be able to edit attributes of the invoice. Not add nor choose from dropdown.
One option would be to provide a custom template for this view. The docs say that you can specify a path to a custom template using ModelAdmin.change_form_template.
Here is a section of the docs that talk about how to override a template: https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#overriding-vs-replacing-an-admin-template
Though this is not the optimal solution, you could probably use Javascript to hide/disable the parts you don't want.
Finally, you may want to consider your usage of the Django admin:
The admin’s recommended use is limited to an organization’s internal
management tool. It’s not intended for building your entire front end
around.
The admin has many hooks for customization, but beware of trying to
use those hooks exclusively. If you need to provide a more
process-centric interface that abstracts away the implementation
details of database tables and fields, then it’s probably time to
write your own views.
def has_add_permission(self, request):
return False
Django admin: How to display a field that is marked as editable=False' in the model?

Django's Admin - Many-to-Many field confusion

I'm teaching myself Django and creating a personal portfolio site. I've setup a model called FolioItem which makes use of a Many-To-Many relation to another model called FolioImage. The idea being each FolioItem can have numerous FolioImages.
class FolioImage(models.Model):
image = models.FileField(upload_to='portfolio_images')
def __unicode__(self):
return self.image.name
class FolioItem(models.Model):
title = models.CharField(max_length=50)
thumbnail = models.FileField(upload_to='portfolio_images')
images = models.ManyToManyField(FolioImage)
def __unicode__(self):
return self.title
In Django's admin interface I can create new FolioItem's but the images field (the many-to-many relating to a FolioImage) is showing all existing FolioImage's added previously to other FolioItems.
Really this should be blank as it is a new item and doesn't have any images associated yet. Is there any way to force this selector to be blank when creating a new item?
Also, it seems when I attempt to edit an existing entry I can't add or delete FolioImage associations (the small green + icon is not present).
Any advice would be great.
I think you are using the wrong relationship here. If you only want FolioImages to belong to a single FolioItem, then you should be using a ForeignKey from FolioImage to FolioItem. You can then configure the admin interface to show the related images for an item as inline formsets, which will allow you to add an edit only the images for that item.
Is there any way to force this
selector to be blank when creating a
new item?
I think you are slightly confused about the interface to the default select multiple widget. It is showing you all the existing images, making them available to you as choices, but there is no relationship on a brand new item. You have to actually click on an item, or do the shift (or control)-click trick to select multiple items, then save your folio item in order to make the relationship.
Also, it seems when I attempt to edit
an existing entry I can't add or
delete FolioImage associations (the
small green + icon is not present).
Again, I think you just need to click or ctrl-click to select/deselect the images you want to associate with your item.
You may also be interested in using Django's cool horizontal or vertical filter instead of the default select multiple interface. You can also use the inline interface. More details are here and here. I think the filter interface is much more intuitive.

Categories