How to add check on admin side actions in django? - python

Here i'm using django latest verion which is 3.1.4 and I just want to add condition in django admin side. I just wanted to return some text in terminal if i update my model from admin panel.
In my case
user submit kyc form
admin person approved that form
user will get notification on approval. (Right now I just want to print some message when admin update his kyc by updating his kyc form by updated approved boolean field.
In short Just wanted to show message when admin updates any model in django admin side.
admin.py
class KycAdmin(admin.ModelAdmin):
list_display = ['__str__','owner']
class Meta:
model = KycModel
def post(self,request):
response = "i'm updated"
print(vu)
return vu
admin.site.register(KycModel,KycAdmin)
If more detail is require then you can just tell me in a comments.

Have you tried overriding the save method in models.
Whenever you save an object, it will hit the save method. You can print whatever you want to over there
class SomeModel(models.Model):
... some fields for eg. name
def save(self, *args, **kwargs):
print(self.name)
super().save(*args, **kwargs)
This is the simplest way to achieve it. You can also override save in admin.

Related

Django Model: ForeignKey and Relations

I have 2 models:
class Post(models.Model):
pass
class Vote(models.Model):
post = models.ForeignKey(Post)
user = models.ForeignKey(django.contrib.auth.models.User)
I want to allow logged User to make a vote on Post's Admin site. I think about 2 solution as below:
Add 'voted' field to Post model.
Customize Post's Admin forms by add a Button control and implement do_vote() function in Post model to call when the Button is clicked.
Do you have any other solutions?
Additionally, I don't know how to implement 2 above solutions.
Could you give me some lines of code?
On your PostAdmin class you can add an action:
class PostAdmin(admin.ModelAdmin):
...
actions = [vote_on_post,]
and then you can implement the vote_on_post method based on this documentation, should be something like this:
#admin.action(description='Vote on action')
def vote_on_post(modeladmin, request, queryset):
user = request.user
for post in queryset:
Vote.objects.create(user=user,post=post)
You probably want to add logic to prevent multiple votes from the same user on the same post, etc.

Python Django - Customizing add user save method

I am pretty new to django framework . I am working on add user form in admin login .I need to send user details to third party API , On success from API call ,have to save in application database . Could you please guide me how to customize user save method to achieve this.
I suggest you override clean() method in UserCreationForm. This way, you can send user details to third party API and validate it.
class CustomUserCreationForm(UserCreationForm):
class Meta:
model=User
def clean(self):
# Send API
class UserAdmin(UserAdmin):
add_form = CustomUserCreationForm
admin.site.register(User, UserAdmin)
clean() method
custom user creation form

Django - can I get the current user when I'm not in a view function

I have Company and CompanyUser models. CompanyUser has 1:1 relationship with the django's auth User model. Every user is part of some company, so I have a ForeignKey field (Company) in the CompanyUser model:
class CompanyUser(models.Model):
Company = models.ForeignKey(Company)
User = models.OneToOneField(User)
Now I want to create some html tables to view and filter the data about Sales, Products, etc. I'm using django-tables2 and that works great.
Now let's say I want to see the Sales of a particular Product. So I need a dropdown that contains all Products of the Company that the user belongs to.
I've have created the forms.py file in my app:
from django import forms
class SaleFilterForm(forms.Form):
product_id = forms.ChoiceField(queryset=Product.objects.all(Company=???))
...
...
So my question is. How to get the current user, when I'm inside forms.py file? I don't have the "request" object there..
Views.py
def yourview(request):
yourform = SaleFilterForm(request.POST, user=request.user)
Forms.py
class SaleFilterForm(forms.Form):
...
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super(SaleFilterForm, self).__init__(*args, **kwargs)
Then you can use your user inside of your form as self.user
Hope it helps!
This is the best simple code in Django to pass user information form views.py to various files is by using a function
in the file, you want to access the current user info (ex:models.py) :
after all imports
`
user = None
def current_user(request):
global user
user = request.user
`
and use the object variable user in the file
in views.py:
from .models import current_user
in any function(eg-def login(request):)
current_user(request)
It is just based on simple sending variable via the function. Simple logic

not saving custom fields to django-allauth - no luck from previous posts

I am trying to create custom fields for users to enter on signup with django-allauth. I have referred to several posts about this, but I am not able to get my custom form to save to my database. I do get a combined form on my signup.html page with username, password1 and 2, email and my extra fields of city and school, but I am not able to save the extra fields to the database. I have run syncdb and can see my User Profile table in the admin area.
This advice is the closest I have come to the answer but I do not understand how to implement it: "You can't use UserProfileForm to the allauth.SIGNUP_FORM_CLASS. You need to extend it from SignUpForm and write a save method which will accept the newly created user as the only parameter," from this post:
Custom registration form for use with django-allauth
I have also attempted to integrate advice on this form these posts:
Django Allauth not saving custom form
How to customize user profile when using django-allauth
This is my code:
Models.py
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
# A required line - links a UserProfile to User.
user = models.OneToOneField(User)
# The additional attributes we wish to include.
school = models.CharField(max_length=128)
city = models.CharField(max_length=128)
def __unicode__(self):
return self.user.username
Forms.py
from django import forms
from django.contrib.auth.models import User
from myapp.models import UserProfile
from django.forms.widgets import HiddenInput
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('city', 'school')
def signup(self, request, user):
user=User.objects.get(email=request.email)
city=request.POST.get('city','')
school=request.POST.get('school','')
userprofile_obj = UserProfile(user=user,city=city,school=school)
userprofile_obj.save()
Settings.py
ACCOUNT_SIGNUP_FORM_CLASS = 'myapp.forms.UserProfileForm'
My template is the basic Signup.html from the django-allauth templates and I do not have a view made for this, although I attempted to make one from the tangowithdjango user authentication section register view, and this gave similar behavior (not saving to the database).
Thanks,
Kelly
Not sure if this is still an active question/issue for the original poster: if so, and for anyone else who comes across this, a few things to correct to at least move in the right direction:
I don't see an __init__() method that calls the superclass? E.g.:
def __init__(self, *args, **kwargs):
super(SignupForm, self).__init__(*args, **kwargs)
use the user parameter to the signup method. It should be populated; don't reload it.
Ensure the two objects are linking correctly (I didn't use Django to build my profile table so YMMV but I set user.profile = Profile(...); then execute user.profile.save() at the end of my signup() method.
get the values to place into the profile from the form cleaned_data (e.g. self.cleaned_data['city'] not the POST.
Then start debugging: is your signup() method firing? What does it get? What happens when you execute the profile.save() method?

Override save_model on Django InlineModelAdmin

I have a model that has a user field that needs to be auto-populated from the currently logged in user. I can get it working as specified here if the user field is in a standard ModalAdmin, but if the model I'm working with is in an InlineModelAdmin and being saved from the record of another model inside the Admin, it won't take.
Here's what I think is the best solution. Took me a while to find it... this answer gave me the clues: https://stackoverflow.com/a/24462173/2453104
On your admin.py:
class YourInline(admin.TabularInline):
model = YourInlineModel
formset = YourInlineFormset
def get_formset(self, request, obj=None, **kwargs):
formset = super(YourInline, self).get_formset(request, obj, **kwargs)
formset.request = request
return formset
On your forms.py:
class YourInlineFormset(forms.models.BaseInlineFormSet):
def save_new(self, form, commit=True):
obj = super(YourInlineFormset, self).save_new(form, commit=False)
# here you can add anything you need from the request
obj.user = self.request.user
if commit:
obj.save()
return obj
I know I'm late to the party, but here's my situation and what I came up with, which might be useful to someone else in the future.
I have 4 inline models that need the currently logged in user.
2 as a created_by type field. (set once on creation)
and the 2 others as a closed_by type field. (only set on condition)
I used the answer provided by rafadev and made it into a simple mixin which enables me to specify the user field name elsewhere.
The generic formset in forms.py
from django.forms.models import BaseInlineFormSet
class SetCurrentUserFormset(forms.models.BaseInlineFormSet):
"""
This assume you're setting the 'request' and 'user_field' properties
before using this formset.
"""
def save_new(self, form, commit=True):
"""
This is called when a new instance is being created.
"""
obj = super(SetCurrentUserFormset, self).save_new(form, commit=False)
setattr(obj, self.user_field, self.request.user)
if commit:
obj.save()
return obj
def save_existing(self, form, instance, commit=True):
"""
This is called when updating an instance.
"""
obj = super(SetCurrentUserFormset, self).save_existing(form, instance, commit=False)
setattr(obj, self.user_field, self.request.user)
if commit:
obj.save()
return obj
Mixin class in your admin.py
class SetCurrentUserFormsetMixin(object):
"""
Use a generic formset which populates the 'user_field' model field
with the currently logged in user.
"""
formset = SetCurrentUserFormset
user_field = "user" # default user field name, override this to fit your model
def get_formset(self, request, obj=None, **kwargs):
formset = super(SetCurrentUserFormsetMixin, self).get_formset(request, obj, **kwargs)
formset.request = request
formset.user_field = self.user_field
return formset
How to use it
class YourModelInline(SetCurrentUserFormsetMixin, admin.TabularInline):
model = YourModel
fields = ['description', 'closing_user', 'closing_date']
readonly_fields = ('closing_user', 'closing_date')
user_field = 'closing_user' # overriding only if necessary
Be careful...
...as this mixin code will set the currently logged in user everytime for every user. If you need the field to be populated only on creation or on specific update, you need to deal with this in your model save method. Here are some examples:
class UserOnlyOnCreationExampleModel(models.Model):
# your fields
created_by = # user field...
comment = ...
def save(self, *args, **kwargs):
if not self.id:
# on creation, let the user field populate
self.date = datetime.today().date()
super(UserOnlyOnCreationExampleModel, self).save(*args, **kwargs)
else:
# on update, remove the user field from the list
super(UserOnlyOnCreationExampleModel, self).save(update_fields=['comment',], *args, **kwargs)
Or if you only need the user if a particular field is set (like boolean field closed) :
def save(self, *args, **kwargs):
if self.closed and self.closing_date is None:
self.closing_date = datetime.today().date()
# let the closing_user field set
elif not self.closed :
self.closing_date = None
self.closing_user = None # unset it otherwise
super(YourOtherModel, self).save(*args, **kwargs) # Call the "real" save() method.
This code could probably be made way more generic as I'm fairly new to python but that's what will be in my project for now.
Only the save_model for the model you're editing is executed, instead you will need to use the post_save signal to update inlined data.
(Not really a duplicate, but essentially the same question is being answered in Do inline model forms emmit post_save signals? (django))
I had a similar issue with a user field I was trying to populate in an inline model. In my case, the parent model also had the user field defined so I overrode save on the child model as follows:
class inline_model:
parent = models.ForeignKey(parent_model)
modified_by = models.ForeignKey(User,editable=False)
def save(self,*args,**kwargs):
self.modified_by = self.parent.modified_by
super(inline_model,self).save(*args,**kwargs)
The user field was originally auto-populated on the parent model by overriding save_model in the ModelAdmin for the parent model and assigning
obj.modified_by = request.user
Keep in mind that if you also have a stand-alone admin page for the child model you will need some other mechanism to keep the parent and child modified_by fields in sync (e.g. you could override save_model on the child ModelAdmin and update/save the modified_by field on the parent before calling save on the child).
I haven't found a good way to handle this if the user is not in the parent model. I don't know how to retrieve request.user using signals (e.g. post_save), but maybe someone else can give more detail on this.
Does the other model save the user? In that case you could use the post_save signal to add that information to the set of the inlined model.
Have you tried implementing custom validation in the admin as it is described in the documentation? Overriding the clean_user() function on the model form might do the trick for you.
Another, more involved option comes to mind. You could override the admin template that renders the change form. Overriding the change form would allow you to build a custom template tag that passes the logged in user to a ModelForm. You could then write a custom init function on the model form that sets the User automatically. This answer provides a good example on how to do that, as does the link on b-list you reference in the question.

Categories