How to save user in Django? - django

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.

Related

How can I apply filter to Django modelform and return form to view in Django?

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})

Owner of the data and superuser should only be able to update the data using CBV

This is my UpdateView. As i have just started django. I am a newbie
views.py
#method_decorator(login_required, name='dispatch')
class ProductUpdateView(UpdateView):
fields = ('product_name', 'product_cost')
model = Product
def form_valid(self, form):
product = get_object_or_404(Product, pk=self.object.pk)
user = self.request.user
if user == product.created_by or user.is_superuser:
pass
else:
raise Http404() #I tried this but it didn't work
I have created a superuser and a user. Superuser should be able to update all the product of both his and everyone else's but user should be only be able to update his product only.
urls.py
urlpatterns = [
url(r'^product/(?P<pk>\d+)/update/$',
login_required(ProductUpdateView.as_view()), name='product_update'),
]
I have a created a product using superuser, which has pk = 1. When i login with some user (Which not superuser) and visit the above url. This user is able to update superuser's product.
models.py
class Product(models.Model):
product_name
product_cost # This two fields and created_by
created_by = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="Product", null=True)
Is there any way that own of the data can update that data and if user tries to access someone else's data it should Http404.
#method_decorator(login_required, name='dispatch')
class ProductUpdateView(UpdateView):
fields = ('product_name', 'product_cost')
model = Product
def user_passes_test(self, request):
if request.user.is_authenticated or request.user.is_superuser:
self.object = self.get_object()
return self.object.user == request.user
return False
def dispatch(self, request, *args, **kwargs):
if not self.user_passes_test(request):
return redirect('someview')
return super(ProductUpdateView, self).dispatch(
request, *args, **kwargs)
i have created a function to check the logged in user is superuser and logged in or not, then passing the object instance to check if it belongs to the user or not
Try doing this as #Exprator did.
def user_passes_test(self, request):
if request.user.is_authenticated:
self.object = self.get_object()
return self.object.created_by == request.user
return False
def dispatch(self, request, *args, **kwargs):
if request.user.is_superuser:
return super(RemitterUpdateView, self).dispatch(request, *args, **kwargs)
elif not self.user_passes_test(request):
return redirect("remitter_search")
return super(RemitterUpdateView, self).dispatch(request, *args, **kwargs)

How to give the information about request.user to clean method

I have a form:
class CreateConferenceForm(forms.ModelForm):
class Meta:
model = Conference
fields = ['name', 'participants']
def clean(self):
cleaned_data = super(CreateConferenceForm, self).clean()
if not request.user.id in cleaned_data.get('participants'):
raise forms.ValidationError('Error')
But I don't know how to import a request object from view, because method is_valid hasn't additional arguments. How I can do it?
Give your form an __init__ method that allows you to pass a user:
def __init__(self, user, *args, **kwargs):
self.user = user
super().__init__(*args, **kwargs)
Now you can use self.user in clean. Wherever you create the form remember to pass the user, e.g. form = CreateConferenceForm(request.user, request.POST) in the view.

how to access/modify django model fields before validating its form in Listview

I have a model Course that has the following attr:
class Course(models.Model):
user= models.ForeignKey(
User,
on_delete=models.CASCADE,
)
# email= models.EmailField(default=user.email)
courseName= models.CharField(max_length=20, blank=False)
class Meta:
unique_together= ('user','courseName',)
def __str__(self):
return self.courseName
I have created a form where I want the user to enter just the courseName and after they POST it, I will add the requested user in the model as well.
This is my form which is getting passed on to the template via my ListView
forms.py
class CourseForm(forms.ModelForm):
class Meta:
model= Course
fields = ['courseName']
**Here is my views.py where I am struggling with **
class CoursesListView(ListView, FormMixin):
model = Course
form_class = CourseForm
template_name = "userApp/courseList.html"
def get_queryset(self):
return Course.objects.filter(user__exact=self.request.user)
def get_context_data(self,*args,**kwargs):
context= super(CoursesListView,self).get_context_data(*args, **kwargs)
context['courseForm'] = self.form_class
return context
def post(self,request, *args, **kwargs):
form = self.form_class(request.POST)
user = User.objects.get(username__exact=self.request.user)
**I want to add the user to my model.user field here**
return self.get(redirect, *args, **kwargs)
def get(self,request, *args, **kwargs):
self.object=None
self.form = self.get_form(self.form_class)
return ListView.get(self, request, *args, **kwargs)
So basically my question is how can I add the user in my model before calling form.is_valid().
something like this?
def post(self,request, *args, **kwargs):
form_data = copy.copy(request.POST)
form_data['user'] = User.objects.get(username__exact=self.request.user).pk
form = self.form_class(form_data)
# form handling follows
return self.get(redirect, *args, **kwargs)
This Answer was suggested by a user who deleted this answer. Didnt get his user id but whoever you were thanks a lot for the help!!!
Just use form.save(commit=False) and then make the necessary changes.
def post(self,request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
user = User.objects.get(username__exact=self.request.user)
instance = form.save(commit=False)
instance.user = user
instance.save()

How can I pass the current user to a custom form validator?

Two scoops of Django advises to make a custom validator for a form as follows:
class MyModel(models.Model):
body = models.TextField()
repo_name = models.CharField(max_length=50)
def validate_repo_existance(value):
# Validate repo existance.
# This needs the Github account which is bound
# to the user account though.
class MyModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(MyModelForm, self).__init__(*args, **kwargs)
self.fields["repo_name"].validators.append(validate_repo_existance)
class Meta:
model = MyModel
Is there any way to pass the user that is on the form page to the custom validator?
This is what I was looking for:
views.py
form = MyModelForm(request.user) # when unbound
form = MyModelForm(request.user, data=request.POST) # when bound
validators.py
class RepoValidator(object):
def __init__(self, user):
self.user = user
def __call__(self, value):
#self.user and value are accessible from here
forms.py
class MyModelForm(forms.ModelForm):
def __init__(self, user, *args, **kwargs):
super(MyModelForm, self).__init__(*args, **kwargs)
self.fields["repo_name"].validators.append(RepoValidator(user))
class Meta:
model = MyModel
The current user is stored in the request object, and can be accessed with request.user. You can pass this user as an argument into the form.
class MyModelForm(forms.ModelForm):
def __init__(self, user, *args, **kwargs):
super(MyModelForm, self).__init__(*args, **kwargs)
self.fields["repo_name"].validator.append(validate_repo_existance)
And pass the user from your view where you instantiate the form:
form = MyModelForm(request.user) # when unbound
form = MyModelForm(request.user, data=request.POST) # when bound
This pattern is used for any other data that you need to pass to a Django form.