I want to customize Django Admin to have specific section for objects of my models (Such as Post or Product models) that use as an archive section.
I now that, I need one field in my models that shown status of objects (Such as is_archive field), but I don't have any idea about how to display them in Django Admin.
Does anyone have an opinion on this?
Create Proxy model for model you need
Create separate section in your admin panel for this proxy model
Override get_queryset() for it.
models.py
from django.db import models
class Post(models.Model):
...
is_archive = models.BooleanField(default = False)
...
class PostProxy(Post):
class Meta:
proxy = True
admin.py
from django.contrib import admin
from .models import *
#admin.register(Post)
class PostAdmin(admin.ModelAdmin):
...
#admin.register(PostProxy)
class PostProxyAdmin(admin.ModelAdmin):
...
def get_queryset(self, request):
return super().get_queryset(request).filter(is_archive=True)
Related
I'm developing a site where I can manually add photographers to the Django adminpanel and then upload the images taken by them.
I used the default User system in Django and added a field here that shows this user is a photographer or not :
from django.contrib.auth.models import AbstractUser
# Create your models here.
class User(AbstractUser):
is_photographer = models.BooleanField(default=True)
Also, in the model that I need to put the images, I used ManyToMany field for photographers (because these photos may have been taken by several people) :
from registration import User
class Photo(models.Model):
...
photographers = models.ManyToManyField(User)
The problem is that when adding a new image to the admin panel, users who are not photographers and the is_photographer is False, is also displayed in the Photographers. I want only users who are photographers to be displayed and not normal users.
You can use Django formfield. Django has placed these formfields for different types of fields. To use formfields in ManyToMany relationships, you can use formfield_for_manytomany in the model admin_class.
Try putting this function in the Photo model admin class in the admin.py file of the application where the Photo model is located, and if you don't have a class admin, create one like this:
from .models import Photo
from django.contrib import admin
from registration.models import User
class PhotoAdmin(admin.ModelAdmin):
def formfield_for_manytomany(self, db_field, request, **kwargs):
kwargs["queryset"] = User.objects.filter(is_photographer=True)
return super(PhotoAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)
admin.site.register(Photo, PhotoAdmin)
In your admin.py file do this:
class PhotoAdmin(admin.ModelAdmin):
def formfield_for_manytomany(self, db_field, request, **kwargs):
kwargs['queryset'] = Users.objects.filter(is_photographer=True)
return super().formfield_for_manytomany(db_field, request, **kwargs)
admin.site.register(Photo, PhotoAdmin)
You can work with the limit_choices_to=… [Django-doc]:
from django.conf import settings
class Photo(models.Model):
# …
photographers = models.ManyToManyField(
setting.AUTH_USER_MODEL,
limit_choices_to={'is_photographer': True}
)
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
Django 1.11.28
I have multiple admin views for my Car model as described in Multiple ModelAdmins/views for same model in Django admin
car/models.py
class Car(models.model):
...
class ProxySportCar(Car):
class Meta:
proxy = True
class ProxyLuxuryCar(Car):
class Meta:
proxy = True
car/admin.py
class CarAdmin(admin.ModelAdmin):
...
admin.site.register(Car, CarAdmin)
class ProxySportCarAdmin(CarAdmin):
model = ProxySportCar
...
admin.site.register(ProxySportCar, ProxySportCarAdmin)
class ProxyLuxuryCarAdmin(CarAdmin):
model = ProxyLuxuryCar
...
admin.site.register(ProxyLuxuryCar, ProxyLuxuryCarAdmin)
My problem is that when i use reverse, Django will return one random admin path amongst the model and proxy ones.
from django.core.urlresolvers import reverse
reverse("admin:admin_car", kwargs={"car_id": Car.objects.last().pk})
# Return one of :
# u'/admin/car/car/710178/'
# u'/admin/car/proxysportcar/710178/'
# u'/admin/car/proxyluxurycar/710178/'
Is it possible to keep the proxy admin views while having reverse always return the base admin path (ie /admin/car/car/ in my case) ?
Hi I am new to Django and I have created a login/logout model Django inbuilt User and UserCreationForm. It is working fine but my issue is I have define two custom inputs in my form and it is displaying on the web page when I run the server but when I check the user under the admin, I only see the details of User defined fields not my custom fields.
How to save it's data to my User model?
or maybe If I defined the custom fields wrong how do I change it so that I can save it's data in my model.
My custom defined fields that is address and phone number is not showing in Admin User and it's data is not getting saved.
model.py
from django.db import models
from django.contrib import auth
# Create your models here.
class User(auth.models.User,auth.models.PermissionsMixin):
def __str__(self):
return "#{}".format(self.username)
forms.py
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm
from django import forms
class UserCreateform(UserCreationForm):
address = forms.CharField(max_length=150, required=True)
phone_number = forms.IntegerField(required=True)
class Meta(UserCreationForm.Meta):
model = get_user_model()
fields = ('username','email','password1','password2')
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
self.fields['username'].label = 'Display Name'
views.py
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import CreateView
from . import forms
# Create your views here.
class SignUp(CreateView):
form_class = forms.UserCreateform
success_url = reverse_lazy('login')
template_name = 'account/signup.html'
Adding fields to a ModelForm doesn't do anything in terms of saving them, if they are not fields of the Model. So of course, address and phone_number aren't saved, your User model doesn't have those fields.
You need to have a Model to save those fields. As explained here, you have two options:
Create a Profile model to save all extra fields
Create a custom User model, subclassing AbstractUser or AbstractBaseUser.
My advice: Do both. Save your extra fields in a Profile model.
And subclass AbstractUser, so you have the option to add useful methods and properties to the User model (right now, just __str__()).
Why not just subclass? Because as your app grows, you'll want to add more an more things to a user's profile. Maybe you want to create different types of profiles, e.g. the private profile and the professional profile. The User itself should be compact, just managing authentication and permissions.
Note: your current User model is wrong. You must not subclass auth.User but auth.AbstractUser.
My project has multiple Models and custom admin pages for the models. All the Models inherit from a "BaseModel". For business functionality, we had to update our "Base model" to include 2 new fields. Given that all models inherit these 2 new fields, they are now showing up in admin pages as editable fields. As per business functionality, these two fields should be displayed as read-only fields
For making fields readonly we normally use readonly_fields = [read only..] in admin class. Is there a way to achieve this without touching all the admin classes?
Create a base admin model class and use it on every admin model class. AFAIK, it will be the best solution you can have
from django.contrib import admin
class BaseModelAdmin:
"""
The base model admin class
"""
readonly_fields = ["field_1", "field_2"]
class FooModelAdmin(BaseModelAdmin, admin.ModelAdmin):
"""
Inheriting the 'BaseModelAdmin' class here
"""
...
class BarModelAdmin(BaseModelAdmin, admin.ModelAdmin):
"""
Inheriting the 'BaseModelAdmin' class here
"""
def get_readonly_fields(self, request, obj=None):
"""
If you have "readonly_fields" that are specific to certain Model, override this method
"""
readonly_fields = super().get_readonly_fields(request, obj=None) + ["bar_field_1", "bar_field_2"]
return readonly_fields
admin.site.register(FooModel, FooModelAdmin) # registering the model in Django admin
admin.site.register(BarModel, BarModelAdmin) # registering the model in Django admin
I have a model named Project which has a m2m field users. I have a task model with a FK project. And it has a field assigned_to. How can i limit the choices of assigned_to to only the users of the current project?
You could do this another way, using this nifty form factory trick.
def make_task_form(project):
class _TaskForm(forms.Form):
assigned_to = forms.ModelChoiceField(
queryset=User.objects.filter(user__project=project))
class Meta:
model = Task
return _TaskForm
Then from your view code you can do something like this:
project = Project.objects.get(id=234)
form_class = make_task_form(project)
...
form = form_class(request.POST)
You need to create a custom form for the admin.
Your form should contain a ModelChoiceField in which you can specify a queryset parameter that defines what the available choices are. This form can be a ModelForm.
(the following example assumes users have an FK to your Project model)
forms.py
from django import forms
class TaskForm(forms.ModelForm):
assigned_to = forms.ModelChoiceField(queryset=Users.objects.filter(user__project=project))
class Meta:
model = Task
Then assign the form to the ModelAdmin.
admin.py
from django.contrib import admin
from models import Task
from forms import TaskForm
class TaskAdmin(admin.ModelAdmin):
form = TaskForm
admin.site.register(Task, TaskAdmin)