add my own class in admin field django-cms - django

Hi everyone Y create my own app in djando CMS, now I want to add my own class and id's to my field.. y try this, but I don't obtain any successful result.
in my model.py I have this
class Entry(models.Model):
TYPES_CHOICES = (
('none', 'not specified'),
('s', 'Series'),
('mb', 'Multiples Bar'),
('b', 'Bar suggestion'),
)
app_config = AppHookConfigField(HealthConfig)
code = models.CharField(blank=True, default='', max_length=250)
url_suggestion = models.CharField(blank=True, default='', max_length=250, verbose_name="URL for Suggestion" )
health_placeholder = PlaceholderField('health_info')
objects = AppHookConfigManager()
def __unicode__(self):
return self.url
class Meta:
verbose_name_plural = 'entries'
and now in my form.py I have this
from django import forms
from .models import Entry
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = '__all__'
def __init__(self, *args, **kwargs):
super(EntryForm, self).__init__(*args, **kwargs)
self.fields['code'].widget.attrs={
'id': 'my_code',
'class': 'code_class',
}
finally my admin.py is like this
from django.contrib import admin
from cms.admin.placeholderadmin import PlaceholderAdminMixin
from .cms_appconfig import HealthConfig
from .models import Entry
from .forms import EntryForm
from aldryn_apphooks_config.admin import ModelAppHookConfig, BaseAppHookConfig
class EntryAdmin(ModelAppHookConfig, PlaceholderAdminMixin, admin.ModelAdmin):
# pass
fieldsets = (
('General data', {
'fields':('app_config','chart', 'url',('count', 'code', 'start'))
}),
('Suggestion',{
'classes':('collapse', 'suggestion',),
'fields':('url_suggestion',('key1_suggestion_name','key1_suggestion'),('key2_suggestion_name','key2_suggestion'), 'primary_suggestions')
}),
)
list_display =('app_config' ,'url', 'chart');
list_filter = (
'app_config',
)
form = EntryForm
class Media:
js = ('health/js/admin/healthAdmin.js',)
css = {
'all': ('health/css/admin/admin_area.css',)
}
admin.site.register(Entry, EntryAdmin)
any idea is I missing something, after that, I do a migrate of the component again.
Thanks in advance!

You can specify a custom form for admin using the form attribute of ModelAdmin.
So using the example from the docs linked below, that would look like;
from django import forms
from django.contrib import admin
from myapp.models import Person
class PersonForm(forms.ModelForm):
class Meta:
model = Person
exclude = ['name']
class PersonAdmin(admin.ModelAdmin):
exclude = ['age']
form = PersonForm
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.form
So in your admin.py you'd need something like;
from .forms import EntryForm
class EntryAdmin(admin.ModelAdmin):
form = EntryForm

Related

How to link to URL of related object in DRF

I’m making a music player with a DRF backend.
I have two models, one is Song and the other is TrackQueue
In the browser, the “nowplaying” instance of TrackQueue shows the meta of the queued song with a link to the file in its meta.
What I need now is a url that always produces that instance of the “nowplaying” TrackQueue (id=1)
What would that url be and how can I create it?
Thank you
models.py
class Song(models.Model):
title = models.CharField(max_length=24)
file = models.FileField()
def __str__(self):
return self.title
class TrackQueue(models.Model):
title = models.CharField(max_length=64)
is_song = models.OneToOneField(Song, on_delete=models.CASCADE)
def __str__(self):
return self.title
Serializers.py
from rest_framework import serializers
from .models import Song, TrackQueue
class SongSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Song
fields = ('id' ,'title', 'file')
class TrackQueueSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = TrackQueue
fields = ('id' , 'title', 'is_song')
views.py
from django.shortcuts import render
from .serializers import SongSerializer
from rest_framework import viewsets
from .models import Song, TrackQueue
from music.serializers import SongSerializer, TrackQueueSerializer
class SongView(viewsets.ModelViewSet):
serializer_class = SongSerializer
queryset = Song.objects.all()
class TrackQueueView(viewsets.ModelViewSet):
serializer_class = TrackQueueSerializer
queryset = TrackQueue.objects.all()

How to prevent IntegrityError in a django model

I am learning django and I follow this blog project on codemy youtube channel: https://www.youtube.com/watch?v=_ph8GF84fX4&ab_channel=Codemy.comCodemy.com
And I wanted to improve my code with ForeignKey but I got stuck.
I want to add a Category into my Post model. So I used the ForeignKey. Not every post has a categroy since I added this model just recently, but I used the default argument in the Category class, which should solve this problem. However, trying several options, I cannot migrate my models and run the server again.
My code:
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
class Category(models.Model):
cat_name = models.CharField(max_length=300, default="uncategorized")
def get_absolute_url (self):
return reverse("blog")
def __str__(self):
return self.cat_name
class Post(models.Model):
title = models.CharField(max_length=300)
author = models.ForeignKey(User, on_delete = models.CASCADE)
body = models.CharField(max_length=30000)
date = models.DateField(auto_now_add=True)
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
def get_absolute_url (self):
return reverse("post", args = [str(self.id)])
The error:
django.db.utils.IntegrityError: The row in table 'blog_post' with primary key '1' has an invalid foreign key: blog_post.category_id contains a value 'uncategorized' that does not have a corresponding value in blog_category.id.
I have used the category in my forms.py:
class PostForm(forms.ModelForm):
class Meta:
model = models.Post
fields = ["title", "author", "category", "body"]
widgets = {
"title": forms.TextInput(attrs={"class": "form-control"}),
"author": forms.Select(attrs={"class": "form-control"}),
"category": forms.Select(attrs={"class": "form-control"}),
"body": forms.Textarea(attrs={"class": "form-control"}),
}
which is used in my views:
from django.shortcuts import render
from django.views.generic.base import TemplateView
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from . import models
from.forms import PostForm
from django.urls import reverse_lazy
class IndexView(TemplateView):
template_name = "index.html"
class PostListView(ListView):
model = models.Post
template_name = "post_list.html"
#ordering = ["-id"]
class PostDetailView(DetailView):
model = models.Post
template_name = "post_detail.html"
class AddPostView(CreateView):
model = models.Post
form_class = PostForm
template_name = "add_post.html"
#fields = ["title", "author", "body"]
class UpdatePostView(UpdateView):
model = models.Post
form_class = PostForm
template_name = "update_post.html"
#fields = ["title", "body"]
class DeletePostView(DeleteView):
model = models.Post
template_name = "delete_post.html"
success_url = reverse_lazy("blog")

Django-jet admin- add button for each row

I want to create a button that deletes the selected row in the table (1 button per row)
admin.py
from django.contrib import admin
from import_export.admin import ImportExportModelAdmin
from import_export.admin import ImportExportMixin
from .models import Applicant
class ApplicantAdmin(ImportExportModelAdmin, admin.ModelAdmin):
list_display = ('Name', 'DOB', 'PhoneNumber', 'Address', 'Batch',
'created_at', 'updated_at',)
list_filter = ('Name', 'Address', 'Batch', 'created_at', 'updated_at',)
list_per_page = 10
# actions = [transferdata, ]
# Register the admin class with the associated model
admin.site.register(Applicant, ApplicantAdmin)
models.py
from django.db import models
from django.utils import timezone
class Applicant(models.Model):
id = models.CharField(max_length=10).primary_key
Name = models.CharField(max_length=50)
DOB = models.CharField(max_length=10)
PhoneNumber = models.CharField(max_length=20)
Address = models.CharField(max_length=200)
Batch = models.CharField(max_length=200)
created_at = models.DateTimeField(default=timezone.now)
updated_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.Name
I already know django-jet that provides this facility a drop-down menu, but for the whole table (i.e. not for the each row)
This problem by creating a function inside the required admin class.
admin.py
import django.contrib import admin
import import_export.admin import ImportExportModelAdmin
import import_export.admin import ImportExportMixin
import .models import Applicant
class ApplicantAdmin(ImportExportModelAdmin, admin.ModelAdmin):
list_display = ('Name', 'DOB', 'PhoneNumber', 'Address', 'Batch',
'created_at', 'updated_at',)
list_filter = ('Name', 'Address', 'Batch', 'created_at', 'updated_at',)
list_per_page = 10
# actions = [transferdata, ]
#staticmethod
def action_button(self):
# assuming the url is saved as 'button_url'
# enter the url to be parsed when the button will be clicked and name the button
return format_html('<a class="button" href="%s">(name of the button)</a>' % button_url)
# Register the admin class with the associated model
admin.site.register(Applicant, AdminApplicant)
Create a function of the button in the views.py
In the urls.py enter the url (almost the same as in admin class) in urlpatterns of the app and call the function present in views.py

Django admin choice field

I have a model that has a CharField and in the admin I want to add choices to the widget. The reason for this is I'm using a proxy model and there are a bunch of models that share this CharField but they each have different choices.
class MyModel(MyBaseModel):
stuff = models.CharField('Stuff', max_length=255, default=None)
class Meta:
proxy = True
class MyModelAdmin(admin.ModelAdmin):
fields = ('stuff',)
list_display = ('stuff',)
admin.site.register(MyModel, MyModelAdmin)
For this model I want to use MY_CHOICES in MyModelAdmin.
Do I override a widget? Do I need to override the whole form?
from django.contrib import admin
from django import forms
class MyModel(MyBaseModel):
stuff = models.CharField('Stuff', max_length=255, default=None)
class Meta:
proxy = True
class MyModelForm(forms.ModelForm):
MY_CHOICES = (
('A', 'Choice A'),
('B', 'Choice B'),
)
stuff = forms.ChoiceField(choices=MY_CHOICES)
class MyModelAdmin(admin.ModelAdmin):
fields = ('stuff',)
list_display = ('stuff',)
form = MyModelForm
admin.site.register(MyModel, MyModelAdmin)
See: https://docs.djangoproject.com/en/dev/ref/forms/fields/#choicefield
You don't need a custom form.
This is the minimum you need:
# models.py
from __future__ import unicode_literals
from django.db import models
class Photo(models.Model):
CHOICES = (
('hero', 'Hero'),
('story', 'Our Story'),
)
name = models.CharField(max_length=250, null=False, choices=CHOICES)
# admin.py
from django.contrib import admin
from .models import Photo
class PhotoAdmin(admin.ModelAdmin):
list_display = ('name',)
admin.site.register(Photo, PhotoAdmin)
You can override formfield_for_choice_field() that way you don't need to create a new form.
class MyModelAdmin(admin.ModelAdmin):
def formfield_for_choice_field(self, db_field, request, **kwargs):
if db_field.name == 'status':
kwargs['choices'] = (
('accepted', 'Accepted'),
('denied', 'Denied'),
)
if request.user.is_superuser:
kwargs['choices'] += (('ready', 'Ready for deployment'),)
return super().formfield_for_choice_field(db_field, request, **kwargs)
See formfield_for_choice_field
You need to override the form the ModelAdmin is going to use:
class MyForm(forms.ModelForm):
stuff = forms.CharField('Stuff', max_length=255, choices=MY_CHOICES, default=None)
class Meta:
model = MyModel
fields = ('stuff', 'other_field', 'another_field')
class MyModelAdmin(admin.ModelAdmin):
fields = ('stuff',)
list_display = ('stuff',)
form = MyForm
If you need your choices to be dynamic, maybe you could do something similar to:
class MyForm(forms.ModelForm):
stuff = forms.CharField('Stuff', max_length=255, choices=MY_CHOICES, default=None)
def __init__(self, stuff_choices=(), *args, **kwargs):
# receive a tupple/list for custom choices
super(MyForm, self).__init__(*args, **kwargs)
self.fields['stuff'].choices = stuff_choices
and in your ModelAdmin's __init__ define what MY_CHOICES is going to be and assign the form instance there instead:
Good luck! :)
in Gerard's answer, if you keep :
def __init__(self, stuff_choices=(), *args, **kwargs):
then when you will try to add new model from admin, you will always get 'This field is required.' for all required fields.
you should remove stuff_choices=() from initialization:
def __init__(self,*args, **kwargs):
You need to think of how you are going to store the data at a database level.
I suggest doing this:
Run this pip command: pip install django-multiselectfield
In your models.py file:
from multiselectfield import MultiSelectField
MY_CHOICES = (('item_key1', 'Item title 1.1'),
('item_key2', 'Item title 1.2'),
('item_key3', 'Item title 1.3'),
('item_key4', 'Item title 1.4'),
('item_key5', 'Item title 1.5'))
class MyModel(models.Model):
my_field = MultiSelectField(choices=MY_CHOICES)
In your settings.py:
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.admin',
#.....................#
'multiselectfield',
)
Watch the MAGIC happen!
Source:
https://pypi.python.org/pypi/django-multiselectfield
Below a solution that works immediately with Postgres' special ArrayField:
# models.py
class MyModel(models.Model):
class Meta:
app_label = 'appname'
name = models.CharField(max_length=1000, blank=True)
ROLE_1 = 'r1'
ROLE_2 = 'r2'
ROLE_3 = 'r3'
ROLE_CHOICES = (
(ROLE_1, 'role 1 name'),
(ROLE_2, 'role 2 name'),
(ROLE_3, 'role 3 name'),
)
roles = ArrayField(
models.CharField(choices=ROLE_CHOICES, max_length=2, blank=True),
default=list
)
# admin.py
class MyModelForm(ModelForm):
roles = MultipleChoiceField(choices=MyModel.ROLE_CHOICES, widget=CheckboxSelectMultiple)
#admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
form = MyModelForm
list_display = ("pk", "name", "roles")
(Django 2.2)

grappelli admin show image

I have a new project on django, in which im using Grappelli and filebrowser, and I have extended the User to have a UserProfile related to it, my question is, how can I modify my code to be able to show on the UserProfile information of a user the profile picture uploaded, and also show it on the Users list?
This is my code now, I dont see any image on the admin!
Admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from models import UserProfile
class UserProfileInline(admin.StackedInline):
model = UserProfile
verbose_name_plural = 'User Profile'
list_display = ('city', 'tel', 'description', 'image_thumbnail',)
class MyUserAdmin(UserAdmin):
list_display = ('username','email','first_name','last_name','date_joined',
'last_login','is_staff', 'is_active',)
inlines = [ UserProfileInline ]
admin.site.unregister(User)
admin.site.register(User, MyUserAdmin)
Models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _
from apps.common.utils.abstract_models import BaseModel
from apps.common.utils.model_utils import unique_slugify
from filebrowser.base import FileObject
from django.conf import settings
class UserProfile(BaseModel):
user = models.OneToOneField(User, related_name="profile")
city = models.CharField(_("City"), max_length=200)
tel = models.CharField(_("Phone Number"), max_length=50,
help_text=_("(Area Code) (Your phone number)"))
description = models.TextField(null=True, blank=True,
help_text = _("Small description about yourself."))
photo = models.ImageField(max_length=255, upload_to="profiles/",
null=True, blank=True, default="img/default_profile_image.png")
def image_thumbnail(self):
if self.photo:
return u'<img src="%s" width="80" height="80" />' % self.photo.version(ADMIN_THUMBNAIL).url
return u'<img src="/site_media/%s" width="80" height="80" />' % settings.DEFAULT_PROFILE_IMAGE
image_thumbnail.allow_tags = True
def __unicode__(self):
if self.user.first_name or self.user.last_name:
return "%s %s" % (self.user.first_name, self.user.last_name)
else:
return self.user.username
Well I got it, first I wanted to show the image chosen on the UserProfile inline section of the user model for the admin and also on the change list of the admin so heres what I
I changed the models.ImageField to sorl ImageField on the model.py of User profile like this
from sorl.thumbnail import ImageField
class UserProfile(BaseModel):
[...]
photo = ImageField(max_length=255, upload_to="profiles/",
null=True, blank=True, default="img/default_profile_image.png")
Then on the admin all I had to do was add sorl's AdminImageMixin on the UserProfileInline class, like this:
from sorl.thumbnail.admin import AdminImageMixin
class UserProfileInline(AdminImageMixin, admin.StackedInline):
model = UserProfile
verbose_name_plural = 'User Profile'
And that way you get an image on the UserProfile Inline section on the admin for that user, now for the change_list.
For the change list I had to do a small callable function inside the admin.py file on the UserAdmin class, heres what I did, using sorl's get_thumbnail:
from sorl.thumbnail import get_thumbnail
class MyUserAdmin(UserAdmin):
def image_thumbnail(self, obj):
im = get_thumbnail(obj.get_profile().photo, '80x80', quality=99)
return u"<img src='/site_media/%s' />" % im
image_thumbnail.allow_tags = True
list_display = ('image_thumbnail', 'username','email','first_name','last_name','date_joined',
'last_login','is_staff', 'is_active',)
And now I have a change list image of the user profile and also on the UserProfile Inline section.
Hope this works for everyone out there... and thanks #pastylegs for your previous answer!
list_display needs to be a callable:
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display
so you can do:
class UserProfileInline(admin.StackedInline):
def image_thumbnail(self, obj):
return obj.image_thumbnail()
image_thumbnail.short_description = 'Thumbnail'
model = UserProfile
verbose_name_plural = 'User Profile'
list_display = ('city', 'tel', 'description', 'image_thumbnail',)