I have a table that only has a handful of entries in it, and it'd be nice if I could use inlines for their list instead of forcing staff to click through to the edit page each time.
That is, when someone clicks on the link that ordinarily gives a list of the model objects, they should instead see the model objects displayed inline.
I tried something like this, but unsurprisingly it gives an error because there's no foreign key:
class MyModelInline(admin.StackedInline):
model = MyModel
class MyModelAdmin(admin.ModelAdmin):
inlines = [MyModelInline,]
admin.site.register(MyModel, MyModelAdmin)
For it to work as you've described you'll need an "editor" model to be a parent for the data. All the rows you want to display should have a foreign key to a single 'editor' model object. So, in models.py:
from django.db import models
class Editor(models.Model):
pass
class MyModel(models.Model):
name = models.CharField(max_length=100) # Field added for demonstration
# ... add any other fields you like ...
editor = models.ForeignKey(Editor)
And in admin.py:
from django.contrib import admin
from Test.models import Editor, MyModel
class MyModelInline(admin.StackedInline):
model = MyModel
class EditorAdmin(admin.ModelAdmin):
inlines = [MyModelInline,]
admin.site.register(Editor, EditorAdmin)
Some other things to consider:
When you make a new MyModel() object programmatically you must always set the foreign key to point to the editor. There should only be one instance of the editor for this to work as you've described. When using the admin interface, this foreign key should be set automatically by using the admin page for the editor object. I would suggest restricting creation and deletion of editor objects for everyone except yourself in production. If someone deletes the editor object then all MyModel objects disappear as well.
Alternative options:
1) If the edits the admin staff is doing are simple then I would recommend implementing "actions" instead.
2) There's also the possibility of overriding the admin template. I personally like this option less because every time Django is updated I have to check that my changes aren't interfering with new features. However, sometimes this is the only way to do some more advanced things in the admin interface. I've done this in my own project, but like to keep the changes minimal.
Related
I have a model that I only want to use one row of its table. So, on admin, I would like to remove the list and add pages, and only edit the existing object. The model is this:
from django.db import models
class Banner(models.Model):
pass
class BannerImg(models.Model):
img = models.ImageField(upload_to="banners")
banner = models.ForeignKey(Banner, on_delete=models.CASCADE)
Basically, the Banner(pk=1) will be loaded by the frontend to display a landing page hero slider. I want multiple images, but also want them to be on the same admin form, so one could order, add or remove images from the same place. Of course having to Banner objects, wouldn't make sense in this case.
I can use inline fields to do the form, but how can I achieve the pages functionality (going directly to edit)?
Thanks!
Accordion to documentation.
from django.contrib import admin
class BannerImgInline(admin.TabularInline):
model = BannerImg
class BannerAdmin(admin.ModelAdmin):
inlines = [
BannerImgInline,
]
Here, by dynamic I mean, I wouldn't want to update my template in order for me to update changes. I'd want them to edit in the admin page on my production site. At first, I thought I'd create a model for "About Me" itself, but then I'd need to create a model for just one instance.
I need help with this, better ways to edit my pages dynamically on the admin site.
Perhaps you could create a model for About Me as you mentioned. Since you've highlighted that you would want to work with the django admin site, then what you could do is to set the permission for only one object to be created for that model which can be updated whenever.
For example:
models.py file.
class AboutMe(models.Model):
# With the desired fields of your choice
Now you can set the permission within the admin.py file to only allow one instance from the model to be created.
from django.contrib import admin
from .models import AboutMe
MAX_OBJECTS = 1
# Using decorator here
#admin.register(AboutMe)
class AboutMeAdmin(admin.ModelAdmin):
fields = ['..', '..', '..'] # fields you want to display on the forms
list_display = ['..', '..', '..'] # fields you want to display on the page for list on objects
# Allowing the user to only add one object for this model...
def has_add_permission(self, request):
if self.model.objects.count() >= MAX_OBJECTS:
return False
return super().has_add_permission(request)
That should be a nice fit for your situation. Also, you can read the docs to learn more about customizing django admin site.
I am building an app in Django.
I found there is a very easy way to integrate a widget into django admin that allows the admin to filter model objects by fields values. That is achieved by including the line
list_filter = ['field_to_filter_by_its_values']
into the class mymodelAdmin(ImportExportModelAdmin) in admin.py, as shown below
class target_area_history_dataAdmin(ImportExportModelAdmin):
resource_class = target_area_history_dataResource
list_filter = ['Target_area_input_data__Name']
admin.site.register(target_area_history_data, target_area_history_dataAdmin)
Now, instead of integrate a widget to filter my model objects by that field, is there a way to integrate a widget to sort my model objects by that field?
Note: I am using Django Import-Export in my model.
I'll suggest you use django-treebeard. This allows you to view tree nodes hierarchically in the administration interface, with interface features dependent upon the tree algorithm used.
# admin.py
from django.contrib import admin
from treebeard.admin import TreeAdmin
from .models import Category
class CategoryAdmin(TreeAdmin):
list_display = ("title", "created", "modified",)
list_filter = ("created",)
admin.site.register(Category, CategoryAdmin)
What's cool about this is that you can not only sort (by clicking the header row) but also drag things around, as shown in this image.
I recommend you using the grapelli admin interface that allows what you need and a bit more. here you have the grapelli project page and the https://github.com/sehmaschine/django-grappelli.
It's a well documented package and is plug and play for what you need. It also gives a fresh face to Django Admin and is compatible with Django import/export package.
in django,i want to extend the auth_user model and adding the 2 fields.one is created_user which will display the date and time when user created something and other is modified_user which will display the date n time when modification is done..
is it possible by migration??
i ve tried dis code..
from django.contrib.auth.models import User, UserManager
class CustomUser(User):
created_user= models.DateTimeField("date and time when created")
modified_user=models.DateTimeField("date and time when modified")
objects= UserManager()
I suggest reading the documentation on creating your own custom user model.
In your particular case, the easiest thing would probably be to subclass AbstractUser and add your fields as above.
If you’re entirely happy with Django’s User model and you just want to add some additional profile information, you can simply subclass django.contrib.auth.models.AbstractUser and add your custom profile fields. This class provides the full implementation of the default User as an abstract model.
Lets say for example I have a Model called "Client" and a model called "PhoneNumbers"
class PhoneNumbers(models.Model):
number = forms.IntegerField()
class Client(models.Model):
number = forms.ManyToManyField(PhoneNumbers)
Client has a ManyToMany relationship with PhoneNumbers. PhoneNumbers has almost 500,000 records in it so when it comes to editing a Client record from a model form with a MultiSelect widget that comes with a M2M filed, it takes forever to load. In fact, it never does. It just sits there trying to load all of those phone objects I am assuming.
My workaround was to so some tedious things with ajax and jquery to edit only the phone numbers in a Client record. Before wasting my time with all of that I wanted to see if there is somehow another way to go about it without having my page hang.
You need to create a custom widget for this field that lets you autocomplete for the correct record. If you don't want to roll your own: http://django-autocomplete-light.readthedocs.io/
I've used this for its generic relationship support, the M2M autocomplete looks pretty easy and intuitive as well. see video of use here: http://www.youtube.com/watch?v=fJIHiqWKUXI&feature=youtu.be
After reading your comment about needing it outside the admin, I took another look at the django-autocomplete-light library. It provides widgets you can use outside the admin.
from dal import autocomplete
from django import forms
class PersonForm(forms.ModelForm):
class Meta:
widgets = {
'myformfield': autocomplete.ModelSelect2(
# ...
),
}
Since Django 2.0, Django Admin ships with an autocomplete_fields attribute that generates autocomplete widgets for foreign keys and many-to-many fields.
class PhoneNumbersAdmin(admin.ModelAdmin):
search_fields = ['number']
class ClientAdmin(admin.ModelAdmin):
autocomplete_fields = ['number']
Note that this only works in the scope of Django admin of course. To get autocomplete fields outside the admin you would need an extra package such as django-autocomplete-light as already suggested in other answers.
Out of the box, the model admin has a raw_id_fields option that let your page load much quicker. However, the user interface of raw id fields isn't very intuitive, so you might have to roll your own solution.
We use this 3rd party widget for this:
https://github.com/crucialfelix/django-ajax-selects
Btw, your 'example' above is really bad DB design for a bunch of reasons. You should just have the phone number as a text field on the Client model and then you would have none of these issues. ;-)