I had a Blog Model. All new blog post has DRAFT status.
In the admin page, admin would be all permissions (CRUD) on the Blog Model. I can solve this by using Django's register method.
What I want is is_staff user can view all the Blog Post but can't update Status (Eg. from DRAFT to APPROVE).
Is there any way to check the request's group, then allow the user to update or not? Thanks.
The simplest solution is to mark the status field as read only in the admin class, by setting readonly_fields:
from django.contrib import admin
from .models import BlogPost
#admin.register(BlogPost):
class BlogPostAdmin(admin.ModelAdmin):
readonly_fields = ('status',)
Note that this makes status read-only for ALL admin users. If you need more fine-grained control based on the current user, there is a get_readonly_fields method you can override.
Also, since ALL users of the Django Admin have is_staff, we'll explicitly check for the built-in permission to change a BlogPost.
class BlogPostAdmin(admin.ModelAdmin):
def get_readonly_fields(self, request, obj=None):
# obj is None if we're creating a new BlogPost, or a BlogPost instance
# if we are editing an existing BlogPost
if not request.user.has_perm("your_app.change_blogpost"):
return ("status",)
return []
Related
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.
Is there a way to send an e-mail to a user when their account is activated through the Django admin application? I can do it independently of the Django admin application but I want the admin to be signed in before they activate a user. Is there a way to achieve this without customizing the Django admin application code? Thanks in advance.
Well, you can override the ModelForm and add the email sending logic in clean method. Also use that modelform in the Admin class. For example:
class UserForm(forms.ModelForm):
manual_activation = forms.BooleanField() # a flag which determines if the user should be manually activated
class Meta:
model = User
fields = '__all__'
def clean(self):
manual_activation = self.cleaned_data.pop('manual_activation', False)
if manual_activation:
# send_email logics
return self.cleaned_data
class UserAdmin(admin.ModelAdmin):
form = UserForm
What will happen is that, in the User admin page, if you click on an user it will show an extra field in the form, named manual_activation. If you check and save the form, then in clean method, you can catch the value of manual_activation and based on that send email.
I am working on a Django Project, where one model (lets say Document) has the following field:
#In models.py
class Document (models.Model):
choice = (('Yes','Yes'), ('No','No'))
authorized = models.CharField (max_length=3, choices=choice, default='No')
Now, as a normal user creates a Document object, the authorized field is no. However, the superior needs to authorize the same before it is actually approved. Now, is there a permission system in django where one user can create an object but not authorize, whereas some other user - who has the permission - can authorize? If not, is the only way to do it is to create a custom field in user model and check it every time?
First of all, why you need to store possible values in CharField and not in BooleanField? I think you should consider changing to BooleanField.
You can do that by providing custom ModelAmin class in admin.py:
from django.contrib import admin
from .models import Document
#admin.register(Document)
class DocumentModelAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
if not request.user.is_superuser:
self.exclude = ['authorized']
return super(DocumentModelAdmin, self).get_form(request, obj, **kwargs)
So now on admin page of Document if it is not a superuser, user won't see authorized field. You can change that code for checking if it should be specific user, or has some permissions, or if user belongs to some Group and etc.
UPDATE
If you want it to be in general views, you can just pass different forms to users, depend on their roles|permissions|groups(i don't know how your so called senior is different from rest of the users). So the answer would be: create two forms, then pass on of them in template based on your request.user attributes.
Django has awesome auth system. I couldn't understand you scenario.
But you could try something like this below
By default every Model object comes with three Permission object like (add_document, change_document and delete_document in your case).
If you want some custom permission you can add it in model Meta class like this:
You can add these permission to User object or Group object.
models.py
class Document (models.Model):
######
class Meta:
permissions = (("Can see document dashbaord", "see_document" ),)
and run python manage.py migrate to create new Permission object with codename as "see_document".
You can implement permissions in request handled by view like this:
view.py
from django.contrib.auth.mixins import PermissionRequiredMixin, permission_required
# For function based view
#pemission_required('document.see_document')
def someview(request):
######
pass
# For class based views
class SomeView(PermissionRequiredMixin, BaseView):
permission_required = 'document.see_document'
This could redirect any user with out the permssion to permission denied page. For more go through this https://docs.djangoproject.com/en/1.10/topics/auth/
Here's a piece of Django admin interface's instance edition form:
How should I change the underlying admin.ModelAdmin instance to make it contain an URL, like this?
Django makes this easy. Subclass ModelAdmin, add a custom method and then tell the Admin how to use it. Here's a sample admin.py:
from django.contrib import admin
from .models import Vendor
class VendorAdmin(admin.ModelAdmin):
readonly_fields = ['example_link']
def example_link(self, obj):
return 'link text'.format(obj.get_link()) # however you generate the link
example_link.allow_tags = True
admin.site.register(Vendor, VendorAdmin)
Here's the documentation that furthers explains readonly_fields, customizing the form label text with short_description, ordering, and how you can put this custom url method on the Model or ModelAdmin.
I just want to know that is it possible to limit the number of objects of a model in admin panel?
It is that, for example, I have a model named 'Homepage' and in the admin panel I don't want a user can create more than one instance of Homepage.
Is there a way I can do this?
If it's just the admin that you want to affect (and don't want to affect the database model), you can create a custom ModelAdmin subclass:
class HomePageAdmin(admin.ModelAdmin):
def add_view(self, request):
if request.method == "POST":
# Assuming you want a single, global HomePage object
if HomePage.objects.count() > 1:
# redirect to a page saying
# you can't create more than one
return HttpResponseRedirect("foo")
return super(HomePageAdmin, self).add_view(request)
# ...
admin.site.register(HomePage, HomePageAdmin)
An alternative strategy to do the same thing is to create a custom ModelForm for HomePage, with a clean method that enforces the single HomePage requirement. This will make your requirement appear as a validation error, rather than as a redirect (or as a database error):
from django import forms
from django.forms.util import ErrorList
class HomePageModelForm(forms.ModelForm):
def clean(self):
if HomePage.objects.count() > 1:
self._errors.setdefault('__all__', ErrorList()).append("You can only create one HomePage object.")
return self.cleaned_data
# ...
class HomePageAdmin(admin.ModelAdmin):
form = HomePageModelForm
# ...
admin.site.register(HomePage, HomePageAdmin)
If it's "one HomePage per user", you will need HomePage to have a ForeignKey to User and adapt the above. You may also need to store the current User object in threadlocals in order to access it from HomePageModelForm.clean
If you want to limit Homepage to one for every user, then you could use one-to-one relation, with OneToOneField. As for limiting to N - a pre_save signal might be useful.
Try
class HomePage(models.Model):
user = models.ForeignKey(User, unique=True)
homepage = models.CharField(max_length=100, unique=True)
class Meta:
unique_together = (("user", "homepage"),)