I am overriding the save method on django model like this
def save(self, *args, **kwargs):
I want to get the current logged in user id on the save method. I can get the currently logged in user id?
Add in settings.py at MIDDLEWARE this line:
'crum.CurrentRequestUserMiddleware',
Then in models.py:
class MyModel(models.Model):
def save(self, *args, **kwargs):
userid = crum.get_current_user()
self.userid = userid.id
super(PlantSpecies, self).save(*args, **kwargs)
userid = models.CharField(max_length=45, blank=True, default=crum.get_current_user())
date = models.DateTimeField(auto_now_add=True)
Then in your forms template you can make the "userid" field hidden. If you look into your database you see that the current userid and date are automatically saed after submitting the form.
Instead of using the Model save method, you can use the save_model of Django ModelAdmin.
from django.contrib import admin
class ArticleAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj.user = request.user
super().save_model(request, obj, form, change)
Please follow the link for details
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_model
Related
I have a model called Client with user field as a foreign key:
class Client(models.Model):
name = models.CharField(_('Client Name'), max_length=100)
address = models.CharField(_('Client Address'), max_length=100, blank=True)
demand = models.PositiveIntegerField(_('Client Demand'))
location = models.PointField(_('Client Location'))
created_at = models.DateTimeField(auto_now=True)
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
class Meta:
default_permissions = ('add', 'change', 'delete', 'view')
def __str__(self):
return self.name
I want to limit the choice of the user field in the admin form based on who logged in
for example, here I logged in as agung, so I want the select box choice of user field limit only to agung, but here I can access other username like admin and rizky.
I tried this
class ClientAdminForm(forms.ModelForm):
class Meta:
model = Client
fields = "__all__"
def __init__(self, request, *args, **kwargs):
super(ClientAdminForm, self).__init__(request, *args, **kwargs)
if self.instance:
self.fields['user'].queryset = request.user
but it seems that it can't take request as an argument (I guess because this is not an Http request)
You can overwrite your Admin Model's get_form method to add the current request.user as class property. Next you can read it in the Form's constructor and filter the query.
class ClientAdmin(admin.ModelAdmin):
# [...]
def get_form(self, request, obj=None, **kwargs):
form_class = super(ClientAdmin, self).get_form(request, obj, **kwargs)
form_class.set_user(request.user)
return form_class
class ClientAdminForm(forms.ModelForm):
# [...]
#classmethod
def set_user(cls, user):
cls.__user = user
def __init__(self, *args, **kwargs):
super(ClientAdminForm, self).__init__(*args, **kwargs)
self.fields['user'].queryset = \
self.fields['user'].queryset.filter(pk=self.__user.pk)
However, is easiest exclude this field in form and update it in the save_model method:
class ClientAdmin(admin.ModelAdmin):
# [...]
def save_model(self, request, obj, form, change):
obj.user = request.user
obj.save()
You can do it by override the base_fields attribute of your form instance like this :
views.py
# Before instantiate the form class
ClientAdminForm.base_fields['user'] = forms.ModelChoiceField(queryset=self.request.user)
# Now you can instantiate the form
form = ClientAdminForm(...)
NB : Do override the base_fields just before instantiate the form
I'm constructing site by Django.
I'm setting some authentications in this site, like Site Manager, Group Manager and Normal User.
When System Manager or Group Manager logged in, they could change the password of Normal Users as a part of system management.
In django, PasswordChangeForm or SetPasswordForm provide some user password change form. I think these forms are for changing password of users themselves.
Yes, I need that too. But I also need the form of changing the password of another users like django admin site.
How can I construct the form ?
I read the code of django's admin site.
I found AdminPasswordChangeForm, can I use this class ?
forms.py
class MyAdminPasswordChangeForm(AdminPasswordChangeForm):
def __init__(self, user, *args, **kwargs):
self.user = user
super().__init__(user, *args, **kwargs)
for field in self.fields.values():
field.widget.attrs['class'] = 'form-control'
views.py
class PasswordChange(PasswordChangeView):
form_class = MyAdminPasswordChangeForm
success_url = reverse_lazy('password_change_done')
template_name = 'accounts/password_change/password_admin_change.html'
def get(self, request, *args, **kwargs):
if 'user_id' in self.request.session:
user = User.objects.get(id=self.request.session['user_id'])
form_class = self.get_form_class()
form = form_class(user=user)
return self.render_to_response(self.get_context_data())
def get_form_class(self):
return self.form_class
you can use set_password() for change user passwords
first you should select user with such code
user=User.objects.get(username=username)
then you can set password
user.set_password(password)
user.save()
I am trying to get user details in model form to create a Service object.Instead of returning all users from my accounts app, I wanted to apply custom filter 'is_admin = False' in object filter but it is returning users without applying filter. Help me to achieve this....
forms.py
from django import forms
from .models import Service
from accounts.models import User
class AddServiceForm(forms.ModelForm):
class Meta:
model = Service
fields = ['service','title','manager','serviceMobile','alternateMobile',
'latitude','longitude','city','street','landmark','keywords']
def __init__(self, user, *args, **kwargs):
super(AddServiceForm, self).__init__(*args, **kwargs)
self.fields['manager'].queryset = User.objects.all().filter(is_admin=False)
views.py code
class AddService(LoginRequiredMixin, LogoutIfNotAdminMixin, CreateView):
login_url = reverse_lazy('mlogin')
permission_required = 'is_staff'
def post(self, request, *args, **kwargs):
context={}
context['city'] = City.objects.all()
if request.method == 'POST':
form = AddServiceForm(request.POST)
if form.is_valid:
form.save()
return redirect('servicedata')
else:
form = AddServiceForm()
return render(request, 'aapp/locations/service/uservicedata.html', {'form': form, 'context': context})
Sorry for my confusion before. But after going through some documentation, I came to know that inside __init__ method, the super should be used after self.fields.
So your changes should be like:
def __init__(self, user, *args, **kwargs):
self.fields['manager'].queryset = User.objects.all().filter(is_admin=False)
super(AddServiceForm, self).__init__(*args, **kwargs)
I found the way for this while fetching objects we can filter using limit_choices_to in model fields like this...
manager = models.ForeignKey(User, on_delete=models.PROTECT, limit_choices_to={'is_admin':False})
In Django, I need to validate unique_together the author and title fields.
The problem is that the author is the request.user so what is the best approach to validate the admin form?
I have this admin:
#admin.register(Document)
class DocumentAdmin(admin.ModelAdmin):
exclude = ('author',)
def save_model(self, request, obj, form, change):
"""Save ``author`` as request user."""
if getattr(obj, 'author', None) is None:
obj.author = request.user
super().save_model(request, obj, form, change)
I can query inside the save_model() and filter both author and title but that doesn't really work well.
I also tried with a forms.ModelForm but I can't manage to get the request.user inside the clean() method.
This is my model:
class Document(models.Model):
title = models.CharField(max_length=32, blank=True)
author = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE
)
class Meta:
unique_together = (('title', 'author'),)
Thank you.
Put a unique_together constrain on your model
class Foo(models.Model):
field_1 = models.CharField(max_length=50)
field_2 = models.CharField(max_length=50)
class Meta:
unique_together = ('field_1', 'field_2')
Django will automatically do the validation for you, if it fails it will throw an IntegrityError (from django.db import IntegrityError)
The author field cannot be excluded from the admin. The solution is to hide the author using the get_form method. The save_model method is still useful if someone tries to change the hidden input value.
#admin.register(Document)
class DocumentAdmin(admin.ModelAdmin):
# exclude = ('author',)
def get_readonly_fields(self, request, obj=None):
"""Make ``author`` field readonly on update."""
return ['author'] if obj else []
def get_form(self, request, obj=None, **kwargs):
"""Hide ``author`` selection default to request user on create."""
form = super().get_form(request, obj, **kwargs)
if not obj:
form.base_fields['author'].initial = request.user
form.base_fields['author'].widget = forms.HiddenInput()
return form
def save_model(self, request, obj, form, change):
"""Save ``author`` field as request user on create."""
if getattr(obj, 'author') != request.user and not change:
obj.author = request.user
super().save_model(request, obj, form, change)
I can't find the answer to this problem which I guessed was very easy for Django.
I simply want to define an author field in a model, like this:
class Article(models.Model):
author = models.ForeignKey(User)
It seems there is no easy way like author = models.ForeignKey(User, default=current_user) so what is the easiest way to store the currently logged in user in the database? (if not logged in, a pre-defined default user called "anonymous" can be used)
Thanks for any help!
Currently logged user is available in the view as the request.user attribute:
def create_article(request):
...
if request.user.is_active():
article.author = request.user
article.save()
...
Alternatively, you can pass request.user to your form class and override the save:
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
def __init__(self, *args, **kwargs):
# Allows you to pass the user in from the request, or just set the property
if not hasattr(self, 'user'):
self.user = kwargs.pop('user')
super(ArticleForm, self).__init__(*args, **kwargs)
def save(self, commit=True)
article = super(ArticleForm, self).save(commit=False)
article.user = self.user
if commit:
article.save()
return article
Slightly more code, but it's encapsulated in the form class and not in the view, so you can use it in more than one place.
Example usage:
# in a view
#login_required
def your_view(request):
form = ArticleForm(request.POST or None, user=request.user)
. . .
# in Django admin
class ArticleAdmin(admin.ModelAdmin):
form = ArticleForm
def get_form(self, request, obj=None, **kwargs):
form = super(ArticleAdmin, self).get_form(request, obj, **kwargs)
form.user = request.user
return form
In either use case, you can be assured you have an authenticated user.