How to save the users last logout time - django

I am looking to save the users last logout time.My idea was to add it to the users profile model. I am using Django 1.11.15
Example:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
...
last_logout = models.DateTimeField(blank=True, null=True)
below is how I created my profile model just for reference
def signup(request):
if request.method == 'POST':
form = UserCreateForm(request.POST or None)
if form.is_valid():
new_user = form.save()
Profile.objects.create(user=new_user)
return redirect('accounts:edit_profile')
else:
form = UserCreateForm()
context = {'form': form}
return render(request, 'accounts/signup.html', context)
Below is what I intend to do. Is this the correct way. I want to add to django's default signout/logout method I am not sure if its called signout or logout
class LoggedOut(TemplateView):
template_name = 'logged_out.html'
def signout(self):
"""logout user """
self.request.user.profile.last_logout = datetime.now()
self.request.user.profile.save()
My URL's
url(r'^loggedout/$', views.LoggedOut.as_view(), name='loggedout'),

You can use Django logout signal for such purpose.
from django.contrib.auth.signals import user_logged_in, user_logged_out
from django.dispatch import receiver
#receiver(user_logged_out)
def sig_user_logged_out(sender, user, request, **kwargs):
user.profile.last_logout = datetime.now()
user.profile.save()

Related

IntegrityError at * NOT NULL constraint failed: main_post.owner_id

I want to create a PostModel(just like instagram) and while the form is created to connect the user to the model with One-to-one/foreign key relationship, anyway I'm getting a problem while trying to upload an image and the db doesn't updates.
I've tried this solution
...
# models.py
from django.contrib.auth.models import User
from django.conf import settings
class Post(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
description = models.CharField(max_length=255, blank=True)
image = models.ImageField(upload_to='images')
uploaded_at = models.DateTimeField(auto_now_add=True)
...
# forms.py
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('description', 'image', )
def save(self, commit=True):
if commit:
Post.save()
return Post
...
# views.py
def account(request):
post = PostForm(request.POST, request.FILES)
if request.method == "POST":
if post.is_valid():
post.save(commit=False)
post.owner = request.user
post.save(commit=True)
messages.success(request, f"you had successfully updated your profile image")
return redirect("main:account")
else:
for msg in form.error_messages:
messages.error(request, f"{msg}: {form.error_messages[msg]}")
return render(request = request,
template_name = "main/account.html",
context={'PostForm':post})
post = PostForm()
return render(request = request,
template_name = "main/account.html",
context={'PostForm':post})
You should not override the def save() method, this is fine as it is now, so:
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('description', 'image', )
# no save
as for the view, you need to add the owner to the object, but here you are adding it to the form, and that thus has no effect (on the object):
from django.contrib.auth.decorators import login_required
#login_required
def account(request):
post = PostForm(request.POST, request.FILES)
if request.method == 'POST':
if post.is_valid():
post.instance.owner = request.user
post.save()
messages.success(request, f'you had successfully updated your profile image')
return redirect('main:account')
# …
I would also advise to rename post to post_form, since this is a form, not a post object.
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].

Django. Populate user name or ID when user saving a model from web pages

My UserImg Model has a user field that has editable=False.
I want this field to be automatically filled in with the user name when the user is saved from web page.
model.py
def upload_myimg_path(instance, filename):
return 'documents/{0}/{1}'.format(instance.created_by.username, filename)
class UserImg(models.Model):
user = models.ForeignKey(User, verbose_name=_('Created by'), on_delete=models.CASCADE, editable=False, null=True, blank=True)
name = models.CharField(max_length=100, default='')
image = models.ImageField(upload_to=upload_myimg_path, verbose_name=_('File'))
def __str__(self):
return str(self.user)
forms.py
class UserImgForm(forms.ModelForm):
class Meta:
model = UserImg
fields = '__all__'
views.py
def createuserimg(request):
if request.method == 'POST':
form = UserImgForm(request.POST or None)
if form.is_valid():
form.save()
return redirect('/accounts/users')
else:
return redirect('/accounts/')
else:
form = UserImgForm
return render(request, 'accounts/user_form.html', {'form': form})
Update your view function to include current logged in user and make use of #login_required decorator to ensure that only logged in users can access this view :
from django.contrib.auth.decorators import login_required
#login_required
def createuserimg(request):
if request.method == 'POST':
form = UserImgForm(request.POST, request.FILES)
if form.is_valid():
obj = form.save(commit=False) # <-- commit=False does not save to database
obj.user = request.user # <-- this allows you to specify the user for your post
obj.save()
return redirect('/accounts/users')
# if the form did not validated, stay on the same page to display errors to your user
else:
form = UserImgForm()
return render(request, 'accounts/user_form.html', {'form': form})
correct answer commit=False allows you to modify the resulting object before it is actually saved to the database. It`s works for me.
Thank you very much for your help
from django.contrib.auth.decorators import login_required
#login_required
def createuserimg(request):
if request.method == 'POST':
form = UserImgForm(request.POST, request.FILES)
if form.is_valid():
link = form.save(commit=False)
link.user = request.user
link.save()
return redirect('/accounts/users')
# if the form did not validated, stay on the same page to display errors to your user
else:
form = UserImgForm()
return render(request, 'accounts/user_form.html', {'form': form})

RelatedObjectDoesNotExist at /post/new/ - Post has no author

I have implemented allauth for user registration and now I am trying to associate the current_user to a post when its being created. When I press 'Submit' I get 'Post has no author' clearly the posts don't recognize the user.
Model:
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.DO_NOTHING)
def __str__(self):
return self.title
View:
def create_post(request, pk=None):
form = PostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author(request.user)
post.save()
else:
form = PostForm()
context = {'form' : form}
return render(request, 'blog/create_post.html', context)
I could really use some pointers, many thanks.
You can set the author instance of the .instance wrapped in the form:
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect
#login_required
def create_post(request, pk=None):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.instance.author = request.user
form.save()
return redirect('name-of-a-view')
else:
form = PostForm()
context = {'form' : form}
return render(request, 'blog/create_post.html', context)
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].
Note: In case of a successful POST request, you should make a redirect
[Django-doc]
to implement the Post/Redirect/Get pattern [wiki].
This avoids that you make the same POST request when the user refreshes the
browser.

NOT NULL constraint failed: core_profile.user_id

I have a model named Profile which is created to extend the User auth model. I have created two forms one is UserForm and ProfileForm. In register.html template I show this two forms and wish to save in the database through the user.
But it constantly shows the exception: Integrity Error
NOT NULL constraint failed: core_profile.user_id
whenever I try to submit the post filling out all the fields and hit submit button.
Here are my models:
from __future__ import unicode_literals
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500, blank=True)
location = models.CharField(max_length=30, blank=True)
birth_date = models.DateField(null=True, blank=True)
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
instance.profile.save()
And here is my view for posting the forms:
from django.contrib.auth.decorators import login_required
from django.contrib.auth import login, authenticate
from django.shortcuts import render, redirect
from .forms import SignUpForm, ProfileForm
#login_required
def home(request):
return render(request, 'home.html')
def signup(request):
if request.method == 'POST':
user_form = SignUpForm(request.POST)
profile_form = ProfileForm(request.POST)
if user_form.is_valid():
user = user_form.save()
profile_form.save()
user.refresh_from_db() # load the profile instance created by the signal
user.profile.birth_date = user_form.cleaned_data.get('birth_date')
user.save()
raw_password = user_form.cleaned_data.get('password1')
user = authenticate(username=user.username, password=raw_password)
login(request, user)
return redirect('home')
else:
user_form = SignUpForm()
profile_form = ProfileForm()
return render(request, 'signup.html', {'user_form': user_form, 'profile_form': profile_form})
And here are the forms:
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import Profile
class SignUpForm(UserCreationForm):
birth_date = forms.DateField(help_text='Required. Format: YYYY-MM-DD')
class Meta:
model = User
fields = ('username', 'password1', 'password2', 'birth_date')
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('bio', 'location')
Thank you,
When you are trying to save the profile_form, it doesn't know to which user it is related to. And in your case, when you save the user form, it will create the profile, and what you need to do is just update the profile of you saved user, so I suggest something like:
def signup(request):
if request.method == 'POST':
user_form = SignUpForm(request.POST)
profile_form = ProfileForm(request.POST)
if user_form.is_valid():
user = user_form.save()
user.profile.bio = profile_form.cleaned_data.get('bio')
user.profile.location = profile_form.cleaned_data.get('location')
user.profile.save()
...
In addition to #Gagik Sukiasyan's answer: I added some additional things to reduce errors / ease your life:
transaction.atomic -> if errors occur, the database is being rolled back
and profile_form.is_valid() makes sure profile_form is validated
instead of going through the profile attributes manually I added a loop
Modified Code:
from django.db import transaction
#transaction.atomic
def register(request):
""" register a new user view """
if request.method == 'POST':
user_form = UserRegisterForm(request.POST)
profile_form = ProfileForm(request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
for field in profile_form.changed_data:
setattr(user.profile, field, profile_form.cleaned_data.get(field))
user.profile.save()

How to relate two django models that are saved by the same form

on the frontsite of my new project I have a form that modifies 2 Django models. In fact, the user has to enter his email, name, a personal goal and a deadline for that goal. "email" and "name" belong to the model "User" while the other two belong to the model "Goal".
I am trying to give the Goal a relation(ForeignKey) to belong to the user but I am unable to do it. I know how to do it if there is a user already existing but in my situation the user and the goal(that belongs to him) are created at the same time.
My View looks like this:
from django.shortcuts import render
from .models import Goal, User
from .forms import GoalForm, UserForm
def front_site(request):
if request.method == "POST":
goal_form = GoalForm(request.POST)
user_form = UserForm(request.POST)
if all([goal_form.is_valid(), user_form.is_valid()]):
user_form.save()
goal_form.save()
return render(request, 'goalapp/single_goal.html', {'user_form': user_form, 'goal_form': goal_form})
else:
user_form = UserForm(request.POST)
goal_form = GoalForm(request.POST)
return render(request, 'goalapp/front_site.html', {'user_form': user_form, 'goal_form': goal_form})
else:
goal_form = GoalForm()
user_form = UserForm()
return render(request, 'goalapp/front_site.html', {'user_form': user_form, 'goal_form': goal_form})
My Models look like this:
from django.db import models
from django.utils import timezone
class User(models.Model):
user = models.CharField(max_length=50)
user_email = models.EmailField()
def __str__(self):
return self.user
class Goal(models.Model):
user = models.ForeignKey('goalapp.User', related_name='goal', on_delete=models.CASCADE, null=True)
goal_body = models.CharField(max_length= 100)
goal_deadline = models.DateTimeField(default=timezone.now)
goal_status = models.IntegerField(default = 1)
def __str__(self):
return self.goal_body
How do I get this to work so that the ForeignKey will be set?
You can get the goal instance by saving the form with commit=False.
user = user_form.save()
goal = goal_form.save(commit=False)
goal.user = user
goal.save()
Just get the user id when saved and assign to Goal
user = user_form.save()
goal.user = user
goal_form.save()