To be more detailed, i have got list of objects in admin panel named Images
class Image(models.Model):
image = models.ImageField(upload_to='products/%Y/%m/%d/',
verbose_name=_('Image'), default='default.png')
album = models.ForeignKey('Album', related_name='images')
category = TreeForeignKey(Category, null=True)
likes = GenericRelation('Like', related_name='image_likes', null=True)
is_main = models.BooleanField(default=False)
is_slider = models.BooleanField(default=False)
seen = models.IntegerField(default=0)
seen_by_admin = models.BooleanField(default=False)
class ImageAdmin(admin.ModelAdmin):
list_display = ['album', 'get_owner', 'is_main', 'is_slider','total_likes', 'seen', 'image_tag', ]
list_filter = ['album', 'album__owner', 'is_main', 'is_slider', 'album__created_at']
search_fields = ['album__name']
list_per_page = 15
Whenever admin or any other superuser enters to any Images.object the seen_by_admin field should be changed to seen_by_admin = True
You could override the save_model method:
class ImageAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj.seen_by_admin=True
super().save_model(request, obj, form, change)
More info:
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_model
Related
I created a ProductAttributes model that have a ForeignKey from Product model
now i'm trying to create an admin panel for adding product using django admin
i'm adding ProductAttributes to Product admin with TabularInline but its not working
this the models and admin classes
#models
class Product(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField()
description = models.TextField(null=True, blank=True)
introduction = models.TextField(null=True, blank=True)
unit_price = models.DecimalField(
max_digits=12,
decimal_places=2,
validators=[MinValueValidator(1)])
inventory = models.IntegerField(validators=[MinValueValidator(0)])
last_update = models.DateTimeField(auto_now=True)
collection = models.ForeignKey(Collection, on_delete=models.PROTECT, related_name='products')
promotions = models.ManyToManyField(Promotion, blank=True)
def __str__(self) -> str:
return self.title
class Meta:
ordering = ['title']
class ProductAttributes(models.Model):
Product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="attributes")
attribute = models.CharField(max_length=255)
#admin
class ProductAttributesInline(admin.TabularInline):
model = models.ProductAttributes
#admin.register(models.Product)
class ProductAdmin(admin.ModelAdmin):
autocomplete_fields = ['collection']
prepopulated_fields = {
'slug': ['title']
}
actions = ['clear_inventory']
inlines = [ProductAttributesInline]
list_display = ['title', 'unit_price',
'inventory_status', 'collection_title']
list_editable = ['unit_price']
list_filter = ['collection', 'last_update', InventoryFilter]
list_per_page = 10
list_select_related = ['collection']
search_fields = ['title']
def collection_title(self, product):
return product.collection.title
#admin.display(ordering='inventory')
def inventory_status(self, product):
if product.inventory < 10:
return 'Low'
return 'OK'
#admin.action(description='Clear inventory')
def clear_inventory(self, request, queryset):
updated_count = queryset.update(inventory=0)
self.message_user(
request,
f'{updated_count} products were successfully updated.',
messages.ERROR
)
class Media:
css = {
'all': ['store/style.css']
}
the ProductAttributes isnt shown in Product admin
in the orginal project i created another inline for ProductImage and its working but when i try to delete that inline its not gone from product admin
Firstly, do not forget checking all migrations, and It would be more good to keep your models in models.py and do not mix them with admin related changes. I would recommend you to write them in admin.py.
You can use both images and attributes like that:
class ProductAttributesInlineAdmin(admin.TabularInline):
model = ProductAttributes
extra = 2
#admin.register(models.Product)
class ProductAdmin(admin.ModelAdmin):
...
inlines = [ProductAttributesInlineAdmin, ProductImageInlineAdmin]
serializers.py
class RegSerializer(serializers.ModelSerializer):
admin = serializers.SlugRelatedField(slug_field='username', read_only=True)
class Meta:
model = Registration
fields = [
'id', 'rooms', 'first_name', 'last_name','admin', 'pasport_serial_num', 'birth_date', 'img', 'visit_date',
'leave_date', 'guest_count', 'room_bool']
models.py
class Rooms(models.Model):
objects = None
room_num = models.IntegerField(verbose_name='Комната')
room_bool = models.BooleanField(default=True, verbose_name='Релевантность')
category = models.CharField(max_length=150, verbose_name='Категория')
price = models.IntegerField(verbose_name='Цена (сум)', null=True)
def __str__(self):
return f'{self.room_num}'
class Meta:
verbose_name = 'Комнату'
verbose_name_plural = 'Комнаты'
class Registration(models.Model):
objects = None
rooms = models.ForeignKey(Rooms, on_delete=models.CASCADE, verbose_name='Номер',
help_text='Номер в который хотите заселить гостя!',
)
first_name = models.CharField(max_length=150, verbose_name='Имя')
last_name = models.CharField(max_length=150, verbose_name='Фамилия')
admin = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='Администратор')
pasport_serial_num = models.CharField(max_length=100, verbose_name='Серия паспорта', help_text='*AB-0123456')
birth_date = models.DateField(verbose_name='Дата рождения')
img = models.FileField(verbose_name='Фото документа', help_text='Загружайте файл в формате .pdf')
visit_date = models.DateField(
default=django.utils.timezone.localdate, verbose_name='Дата прибытия')
leave_date = models.DateField(blank=True, null=True, verbose_name='Дата отбытия', default='После ухода!')
guest_count = models.IntegerField(default=1, verbose_name='Кол-во людей')
room_bool = models.BooleanField(default=False, verbose_name='Релевантность',
help_text='При бронирование отключите галочку')
price = models.IntegerField(verbose_name='Цена (сум)', null=True)
def __str__(self):
return f'{self.rooms},{self.last_name},{self.first_name},{self.room_bool}'
class Meta:
verbose_name = 'Номер'
verbose_name_plural = 'Регистрация'
how can I make it so that the name of the user who registered room is indicated in the admin field and without the right to change only readonly?
can this be done at all?
thanks in advance for your reply
You can pass additional attributes to serilizer's save method. In your view, you can call serializer save() with admin argument like this:
def your_view(request):
# your code
serializer.save(admin=request.user)
Or if you want to do it on admin page, you can override your admin's save_model method. Also you should specify admin as a readonly:
class RegistrationAdmin(admin.ModelAdmin):
readonly_fields = ('admin',)
def save_model(self, request, obj, form, change):
if not obj.pk:
# Only set admin during the first save.
obj.admin = request.user
super().save_model(request, obj, form, change)
I set serializers.HiddenField and by default set CurrentUserDefault() from serializers
automatically substitutes the value of the current admin and at the same time the admin field now goes to the api
class RegSerializer(serializers.ModelSerializer):
admin = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = Registration
exclude = ['price', 'visit_date']
i want to hide a specific line of my Django Admin Model by permission or Group
My models.py
class Post(models.Model):
title = models.CharField(max_length=128)
slug = AutoSlugField(populate_from='title')
category = models.CharField(max_length=64, choices=CATEGORY_CHOICES, default='actus')
is_verified = models.BooleanField(default=False)
content = RichTextField(blank=True, null=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
thumbnail = models.ImageField(upload_to='media/thumbs', blank=True, null=True, default="media/thumbs/default.jpg")
date = models.DateTimeField(auto_now_add=True, blank=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("post", kwargs={"slug": self.slug, "category": self.category})
My Model admin
from django.contrib import admin
from django.db import models
from django.db.migrations.graph import Node
from django.utils.regex_helper import Group
from .....models import Post
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'date', 'is_verified')
list_filter = ('date', 'author', 'is_verified')
admin.site.site_header = 'Staff Dashboard'
admin.site.register(Post, PostAdmin)
My django admin page
Django admin page
If someone has an idea
You can define two ModelForms: one with the is_verified option, and one without, so:
# app_name/forms.py
from django import forms
from app_name.models import Post
class NormalUserPostForm(forms.ModelForm):
class Meta:
model = Post
exclude = ['is_verified']
class AdminUserPostForm(forms.ModelForm):
class Meta:
model = Post
fields = '__all__'
then we can override the get_form method of the ModelAdmin:
# app_name/admin.py
from app_name.forms import NormalUserPostForm, AdminUserPostForm
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'date', 'is_verified')
list_filter = ('date', 'author', 'is_verified')
form = NormalUserPostForm
def get_form(self, request, obj=None, **kwargs):
if request.user.is_superuser:
kwargs['form'] = AdminUserPostForm
return super().get_form(request, obj, **kwargs)
admin.site.site_header = 'Staff Dashboard'
admin.site.register(Post, PostAdmin)
You can change the condition to request.user.has_perm('some_permission') to check for a certain permission instead.
I am trying to get the most out of my Django Blog project and wanted to know how to show in the admin the activities that a user has made like making comments or giving likes to posts.
I need some hints and guidance on how to add this information in the admin.py
Here is the models.py in Blog App
class Post(models.Model):
title = models.CharField(max_length=100, unique=True)
content = RichTextUploadingField(null=True, blank=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='author')
date_posted = models.DateTimeField(default=timezone.now)
slug = models.SlugField(blank=True, null=True, max_length=120)
liked = models.ManyToManyField(User, default=None, blank=True, related_name='liked')
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post-detail', kwargs={'slug': self.slug})
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
class Meta:
verbose_name_plural = 'Blog Posts'
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
content = models.TextField(max_length=300)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.post}-{self.user}-Comment No.{self.pk}"
LIKE_CHOICES = (
('Like', 'Like'),
('Unlike', 'Unlike')
)
class Like(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
value = models.CharField(choices=LIKE_CHOICES, max_length=8)
created = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.post}-{self.user}-{self.value}"
Here is the models.py in Users App
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
This is what I have tried in the models.py in Users app but didn't work
# Get the no. of posts
def get_posts_no(self):
return self.author.all().count()
# Get the no. of likes
def get_likes_given(self):
likes= set.like_set.all()
total_liked=0
for item in likes:
if item.value=='Like':
total_liked+=1
return total_liked
"... to add this information in the admin.py" → do you mean to say that you would like to show an additional column in the Django admin site with said information? If so, then the answer is:
In your admin.py, extend the PostAdmin class with a custom queryset and add comments_count and likes_count to list_display = (...):
from django.contrib import admin
from django.db.models import Count
from .models import Post
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'date_posted', 'comments_count', 'likes_count')
def get_queryset(self, request):
queryset = super().get_queryset(request)
queryset = queryset.annotate(
_comments_count=Count('comment_set', distinct=True),
_likes_count=Count('like_set', distinct=True)
)
return queryset
def comments_count(self, obj):
if hasattr(obj, '_comments_count'):
return obj._comments_count
return None
def likes_count(self, obj):
if hasattr(obj, '_likes_count'):
return obj._likes_count
return None
comments_count.admin_order_field = '_comments_count'
likes_count.admin_order_field = '_likes_count'
admin.site.register(Post, PostAdmin)
When a user creates a post using the CreateView I want it so when a user submits the Post, they then see the post they just made. But for some reason my get_absolute_url() is not working.
Prior to this I started to work on slugifying the Post and Category models and haven't been able to see if they work due to the fact get_absolute_url won't work.
Models:
class Category(models.Model):
title = models.CharField(max_length=200)
colorcode = models.CharField(max_length=20, blank=True, null=True)
description = models.TextField()
image = models.ImageField(blank=True, null=True)
slug = models.SlugField(unique=True)
def __str__(self):
return self.title
class Post(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, blank=True, null=True)
image = models.ImageField(blank=True, null=True)
live = models.BooleanField(default=False)
slug = models.SlugField(unique=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'slug': self.slug})
def create_slug(instance, new_slug=None):
slug = slugify(instance.title)
if new_slug is not None:
slug = new_slug
qs = Post.objects.filter(slug=slug).order_by("-pk")
exists = qs.exists()
if exists:
new_slug = "%s-%s" %(slug, qs.first().pk)
return create_slug(instance, new_slug=new_slug)
return slug
def pre_save_post_reciever(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = create_slug(instance)
pre_save.connect(pre_save_post_reciever, sender=Post)
Views:
class IndexView(ListView):
model = Post
queryset = Post.objects.filter(live=True)
template_name = "public/index.html"
class PostEdit(object):
model = Post
fields = '__all__'
success_url = '/'
class PostCreateView(LoginRequiredMixin, PostEdit, CreateView):
fields = ['title', 'text', 'category', 'image']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class PostUpdateView(LoginRequiredMixin, PostEdit, UpdateView):
fields = ['title', 'text', 'category', 'image']
Anyone has any idea on how to fix this?
If behaves according to this definition:
class PostEdit(object):
model = Post
fields = '__all__'
success_url = '/' # <<<---
In your case success_url is not static and cannot be defined as attribute. You have to override get_success_url instead like that:
def get_success_url(self):
return self.get_object().get_absolute_url()
also have a look at this answer.
upd
If the redirect is that simple then, as Daniel Roseman mentioned, you don't need to specify success_url at all - what you want is the default behavior.
You don’t even need to provide a success_url for CreateView or UpdateView - they will use get_absolute_url() on the model object if available.