How to hide specific field by User Group on a django admin - python

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.

Related

Way to fix "missing QuerySet" and "override QuerySet" with Django

I'm trying to code a blog with django but I want to add a placeholder to my form when creating or editing an article. So I had the forms.py because before that I wasn't using a form from this file because I only needed the models.py file. I fount a way to do what I wanted and so add my placeholder into my input from my forms. But one problem, when I updated my website and went to my pages to see the changed an error appeared.
So I tried to fix the problem by looking on the web and I saw a lot of people having approximately the same problem but the answers were that I had to add a get_queryset definition in my views in views.py for the specific forms. I didn't find what I have to set in the definition of the get_queryset and not very understood where I have to put these definitions. I would be very grateful if you can help me.
Here's my code :
My views in view.py :
class BlogHome(ListView):
model = BlogPost
context_object_name = "posts"
def get_queryset(self):
queryset = super().get_queryset()
if self.request.user.is_authenticated:
return queryset
else:
return queryset.filter(published=True)
#method_decorator(login_required, name='dispatch')
class BlogPostCreate(CreateView):
form_name = UpdatePostForm
class BlogPostEdit(UpdateView):
form_name = CreatePostForm
My urls.py :
urlpatterns = [
path('create/', BlogPostCreate.as_view(), name="create"),
path('edit/<str:slug>/', BlogPostEdit.as_view(), name="edit"),
My forms.py :
from django import forms
from posts.models import BlogPost
class UpdatePostForm(forms.Form):
model = BlogPost
template_name = 'posts/blogpost_edit.html'
fields = [
'title',
'slug',
'content',
'published',
'author',
'created_on'
]
class Meta:
title = forms.CharField(
widget = forms.TextInput(attrs={'placeholder' : 'Enter the title of the article'}),
),
slug = forms.CharField(
widget = forms.TextInput(attrs={'placeholder' : 'Enter the title of the article'}),
),
content = forms.CharField(
widget = forms.TextInput(attrs={'placeholder' : 'Enter the title of the article'}),
),
created_on = forms.CharField(
widget = forms.TextInput(attrs={'placeholder' : 'Enter the date of creation'}),
),
class CreatePostForm(forms.Form):
model = BlogPost
template_name = 'posts/blogpost_create.html'
fields = [
'title',
'slug',
'content',
'published',
'author',
'created_on'
]
class Meta:
title = forms.CharField(
widget = forms.TextInput(attrs={'placeholder' : 'Enter the title of the article'}),
),
slug = forms.CharField(
widget = forms.TextInput(attrs={'placeholder' : 'Enter the title of the article'}),
),
content = forms.CharField(
widget = forms.TextInput(attrs={'placeholder' : 'Enter the title of the article'}),
),
created_on = forms.CharField(
widget = forms.TextInput(attrs={'placeholder' : 'Enter the date of creation'}),
),
My models.py :
from django.contrib .auth import get_user_model
from django.template.defaultfilters import slugify
from django.db import models
from django import forms
from django.urls import reverse
User = get_user_model()
class BlogPost(models.Model):
title = models.CharField(max_length=255, unique=True, verbose_name="Titre")
slug = models.SlugField(max_length=255, unique=True, blank=True)
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
last_updated = models.DateTimeField(auto_now=True)
created_on = models.DateField(blank=True, null=True)
published = models.BooleanField(default=False, verbose_name="PubliƩ")
content = models.TextField(blank=True, verbose_name="Contenu")
thumbnail = models.ImageField(blank=True, upload_to='blog')
class Meta:
ordering = ['-created_on']
verbose_name = "Article"
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super().save(*args, **kwargs)
#property
def author_or_default(self):
return self.author.username if self.author else "L'auteur inconnu"
def get_absolute_url(self):
return reverse('posts:home')
class BlogPostCreate(CreateView):
form_class = UpdatePostForm
template_name = 'update_post.html'
success_url = 'success'
OR
class BlogPostCreate(CreateView):
model = UpdatePost
Try the above. Please remove #method_decorator(login_required, name='dispatch') from this class view because its a class view not a method.
Your form should be a model for I expect.
class CreatePostForm(forms.ModelForm):
I am updating my answer as per your last comment. Check this for django modelForm. You need to add a meta in your form:
class CreatePostForm(forms.ModelForm):
class Meta:
model = User
fields = ['...', ....]

How to solve the NOT NULL constraint failed Error in Django

I am getting an IntegrityError when I want to save a new course on my e-learning website. Of course, I have searched for a similar solution on StackOverflow but I couldn't find an appropriate way for my solution.
here are my models
UserAccount Model
from django.db import models
from django.contrib.auth.models import AbstractUser
class UserAccount(AbstractUser):
email = models.EmailField(
max_length=255, verbose_name='email', unique=True)
username = models.CharField(max_length=255, unique=True)
is_student = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
Course Model
from django.db import models
from accounts.models import UserAccount
class Course(models.Model):
owner = models.ForeignKey(
UserAccount, related_name='courses_created', on_delete=models.CASCADE)
title = models.CharField(max_length=200)
slug = models.SlugField()
description = models.TextField()
cover_photo = models.ImageField(upload_to="cover/", null=True, blank=True)
Also, my course form is here
class CourseForm(forms.ModelForm):
class Meta:
model = Course
fields = ['curriculum', 'title', 'description', 'cover_photo']
widgets = {
'description': forms.Textarea(attrs={'rows': 3})
}
So in my view, I like to send the list of my courses to the template and also my CourseForm() using the get_context_data method. The code is bellow
My class-based view
class OwnerListMixin(object):
def get_queryset(self):
qs = super().get_queryset()
return qs.filter(owner=self.request.user)
class OwnerCourseMixin(OwnerListMixin, LoginRequiredMixin, PermissionRequiredMixin):
model = Course
fields = ['curriculum', 'title', 'description', 'cover_photo']
success_url = reverse_lazy('manage_course_list')
class ManageCourseListView(OwnerCourseMixin, ListView):
template_name = "courses_app/manage/course/list.html"
permission_required = "courses_app.view_course"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'] = CourseForm()
return context
but when I render the form in my template to save a new course I get the following Error
IntegrityError at /create/
NOT NULL constraint failed: courses_app_course.owner_id
CREATE VIEW
class CourseCreateView(OwnerCourseMixin, CreateView):
permission_required = "courses_app.add_course"
template_name = "courses_app/manage/course/form.html"
success_url = reverse_lazy("manage_course_list")
You need to set the user as the owner what currently is not happening. The form is being saved with the fields you have set. There are multiple ways of adding the user. You could do it this way.
from django.shortcuts import redirect
class CourseCreateView(OwnerCourseMixin, CreateView):
permission_required = "courses_app.add_course"
template_name = "courses_app/manage/course/form.html"
success_url = reverse_lazy("manage_course_list")
def form_valid(self, form):
instance = form.save(commit=False)
instance.owner = self.request.user
instance.save()
return redirect(self.get_success_url())

Am having troubles with django-parler 2.0.1 after i had applied migration to translations, it won't show Products fields in admin site

this is my setting for translations in the models.py file, django-parler 2.0.1 won't show fields for Products in the admin site after I had synch migrations. I am currently using Django 3.0.3.
from django.db import models
from django.urls import reverse
from parler.models import TranslatableModel, TranslatedFields
class Category(TranslatableModel):
translations = TranslatedFields(
name = models.CharField(max_length=200,
db_index=True),
slug = models.SlugField(max_length=200,
db_index=True,
unique=True)
)
class Meta:
# ordering = ('name',)
verbose_name = 'category'
verbose_name_plural = 'categories'
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('shop:product_list_by_category',
args=[self.slug])
class Product(TranslatableModel):
translations = TranslatedFields(
name = models.CharField(max_length=200, db_index=True),
slug = models.SlugField(max_length=200, db_index=True),
description = models.TextField(blank=True)
)
category = models.ForeignKey(Category,
related_name='products',
on_delete=models.CASCADE)
image = models.ImageField(upload_to='products/%Y/%m/%d',
blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
available = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
#class Meta:
# ordering = ('name',)
# index_together = (('id', 'slug'),)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('shop:product_detail',
args=[self.id, self.slug])
I have registered the model in the admin.py file but it won't show the fields for product description and price all I get is the translated tab.
from django.contrib import admin
from .models import Category, Product
from parler.admin import TranslatableAdmin
#admin.register(Category)
class CategoryAdmin(TranslatableAdmin):
list_display = ['name', 'slug']
def get_prepopulated_fields(self, request, obj=None):
return {'slug': ('name',)}
#admin.register(Product)
class ProductAdmin(TranslatableAdmin):
list_display = ['name', 'slug', 'price',
'available', 'created', 'updated']
list_filter = ['available', 'created', 'updated']
list_editable = ['price', 'available']
def get_prepopulated_fields(self, request, obj=None):
return {'slug': ('name',)}
I wonder what am doing wrong that I am getting this and I wonder if there's a better way to make translate configurations with Django-parler 2.0.1. any suggestions is welcomed!!
Apparently, I was able to fix the problem by first deleting all migrations and I also had to trash my database and switch to PostgreSQL and after that, I reapplied migrations and it worked. All fields are now visible in the admin site now yippee! but be mindful to make a backup of your database because everything will be deleted..

Django: How can i detect object request in admin panel?

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

SystemCheckError (slug in django)

I got this error (what is wrong here? I can't find the root cause of this. I tried to search for this answer but it didn't applied to this case.):
django.core.management.base.SystemCheckError: SystemCheckError: System check identified some issues:
ERRORS:
<class 'rango.admin.CategoryAdmin'>: (admin.E027) The value of 'prepopulated_fields' refers to 'slugs', which is not an attribute of 'rango.Category'.
My admin.py
from django.contrib import admin
from .models import Category, Page
class CategoryAdmin(admin.ModelAdmin):
prepopulated_fields = {'slugs':('name',)}
class PageAdmin(admin.ModelAdmin):
list_display = ('title', 'category', 'url')
admin.site.register(Category, CategoryAdmin)
admin.site.register(Page, PageAdmin)
My models.py
from django.db import models
from django.template.defaultfilters import slugify
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
views = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
class Meta:
verbose_name_plural = 'Categories'
def __str__(self):
return self.name
class Page(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
title = models.CharField(max_length=128)
url = models.URLField()
views = models.IntegerField(default=0)
def __str__(self):
return self.title
You have field named slug in your model, but you are using slugs in admin. You need to change it to slug also:
class CategoryAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug':('name',)}

Categories