Django execute custom code after user signup - django

I have a users app in a Django project (version 2.1 and python 3.6). After an user signup (both front end and when added in the admin dashboard ideally), I'd like to insert data in one other table. I know how to insert data, but I didn't find out how to do it right after a successfull signup.
Ideal answer would just show me how to do something like print('hello') right after an user created his account.
# users/admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from .forms import CustomUserCreationForm, CustomUserChangeForm
from .models import CustomUser
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
model = CustomUser
list_display = ['email', 'username',]
admin.site.register(CustomUser, CustomUserAdmin)
# users/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm):
model = CustomUser
fields = ('username', 'email')
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = ('username', 'email')
# users/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
# add additional fields in here
credit = models.IntegerField(default=200) # editable=False
def __str__(self):
return self.email
# users/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('signup/', views.SignUp.as_view(), name='signup'),
]
# users/views.py
from django.urls import reverse_lazy
from django.views import generic
from .forms import CustomUserCreationForm
class SignUp(generic.CreateView):
form_class = CustomUserCreationForm
success_url = reverse_lazy('login')
template_name = 'signup.html'

Use a post-save signal
https://docs.djangoproject.com/en/2.1/ref/signals/
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=User)
def say_hello(sender, instance, **kwargs):
if instate._state.adding:
print('hello')
Signal is better than a method on the view because the User may be created some way other than through the view e.g , via the shell, a management command, a migration, a different view, etc.
Note the _state is not "private" so don't feel bad about using it, it's just named that way to avoid clashing with field names.
Check _state instead of more common checking instance.pk because instance.pk is always present when primary key is a natural key rather than AutoField

I think the best approach would be overriding save method of CustomUser model. For example:
class CustomUser(AbstructUser):
def save(self, *args, **kwargs):
user = super(CustomUser, self).save(*args, **kwargs)
print("Hello World")
return user
Check here in Django documentation for more details: https://docs.djangoproject.com/en/2.1/topics/db/models/#overriding-predefined-model-methods.

Related

UpdateView - save as new record

What's the best method of saving an existing record as a new record when in a specific view?
I cannot use default values in a CreateView because the defaults will change depending on the type of record the user is creating.
models.py
class videos(models.Model):
title = models.CharField(max_length=250)
fk_type = models.ForeignKey('mediaTypes',on_delete=models.CASCADE)
b_template = models.BooleanField(default=False)
class mediaTypes(models.Model):
name = models.CharField(max_length=250)
e.g.
1 - Football game - 4 - TRUE
2 - Superbowl X highlights - 4 - FALSE
3 - Superbowl XX highlights - 4 - FALSE
4 - Home movies - 2 - TRUE
5 - Finding Holy Gail under house - 2 - FALSE
forms.py
from django import forms
from django.forms import ModelForm
from .models import (videos)
class create_football(ModelForm):
class Meta:
model = videos
fields = '__all__'
views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.urls import reverse
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth.models import User, AbstractBaseUser, BaseUserManager, PermissionsMixin
from django.contrib.auth.decorators import login_required
from django.db.models import Q # filter using operators '&' or '|'.
from django.utils import timezone
from users.models import Profile
from django.forms import ModelForm
from django.http import HttpResponseRedirect
from .models import (videos)
from .forms import (create_football)
class templates(LoginRequiredMixin, ListView):
model = videos
template_name = 'videos/templates.html'
context_object_name = 'video'
def get_queryset(self):
profile = get_object_or_404(Profile, user=self.request.user)
queryset = videos.objects.filter(Q(fk_type="4")
return queryset
class create_football(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = videos
form_class = create_football
template_name = 'videos/create_football.html'
def form_valid(self, form):
messages.success(self.request, 'form is valid')
form.instance.user = self.request.user
form.save()
To create a new football video, the user selects the record titled 'football game' from the templates view - which opens an update view. This dummy template record has the fk_type and other fields automatically set to the appropriate value.
I need this view to save the changes the user will make, such as to the title, as a new record.

How to integrate mixpanel to django backend

I am new with integrating mixpanel to Django backend to track events,As i try to track, it gives me empty brackets anyone with ideas or resources please help me am quite stack
views.py
from django.shortcuts import render
from django.views import View
from rest_framework.generics import ListCreateAPIView
from rest_framework.views import APIView
from rest_framework.response import Response
from .serialize import UserSerializer, TweakSerializer, ChannelSerializer, SubscriberSerializer
from tweaks.models import Tweak
from accounts.models import User
from channels.models import Channel, Subscriber
from mixpanel import Mixpanel
import json
# Create your views here.
mp = Mixpanel('TOKEN')
class userApi(ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
def get(self, request):
queryset = self.get_queryset()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
apiuser=userApi()
point = json.dumps(apiuser.__dict__)
mp.track(point, 'users')
serializers.py
from rest_framework import routers, serializers, viewsets
from django.urls import path, include
from accounts.models import User
from tweaks.models import Tweak
from channels.models import Channel, Subscriber
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = 'username', 'email', 'first_name', 'last_name', 'date_joined'

Use custom UserCreationForm with GeoDjango admin (OSMGeoAdmin)

Django==2.2.1
GDAL==2.3.2
django-username-email==2.2.4
I have a simple Django application with a custom user model based on django-username-email's AbstractCUser, which removes the username from the user model, using e-mail address instead. On the user model, I defined a PointField field storing the user's current location.
models.py
from django.contrib.gis.db import models as gis_models
from cuser.models import AbstractCUser
class User(AbstractCUser):
"""Custom user model that extends AbstractCUser."""
current_location = gis_models.PointField(null=True, blank=True,)
I would like to register this model in Django admin so that I can register new users and view/set their location with a map widget. This kind of works if I use a custom user admin based on admin.OSMGeoAdmin in combination with a custom user change form:
admin.py
from django.contrib.gis import admin
from django.contrib.auth import get_user_model
from .forms import CustomUserCreationForm, CustomUserChangeForm
class CustomUserAdmin(admin.OSMGeoAdmin):
model = get_user_model()
add_form = CustomUserCreationForm # <- there seems to be a problem here
form = CustomUserChangeForm
list_display = ['email', 'last_name', 'first_name']
readonly_fields = ['last_login', 'date_joined']
admin.site.register(get_user_model(), CustomUserAdmin)
forms.py
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = get_user_model()
exclude = ('username',)
class CustomUserChangeForm(UserChangeForm):
class Meta(UserChangeForm.Meta):
model = get_user_model()
fields = (
'email',
'first_name',
'last_name',
'current_location',
# ...
)
When I open an existing user record in the Django admin, the required fields are displayed as intended, and the current location is displayed on a map. However, the same form seems to be used for user creation as well (i.e. add_form has no effect), which makes it impossible to add new users via the admin, because the password setting functionality is not embedded correctly (see screen shot).
The problem seems to be that OSMGeoAdmininherits from ModelAdmin, which in contrast to the standard UserAdmindoes not have an add_form property.
Is there any way to specify a custom user creation form in this case (ideally the UserCreationForm provided by django-username-email while maintaining the ability to display point fields on a map on the user change form?
You need to override get_form similar to how django.contrib.auth.admin.UserAdmin does.
def get_form(self, request, obj=None, **kwargs):
"""
Use special form during user creation
"""
defaults = {}
if obj is None:
defaults['form'] = self.add_form
defaults.update(kwargs)
return super().get_form(request, obj, **defaults)
Following schillingt's suggestion, this is the code I ended up using:
from django.contrib.gis import admin
from django.contrib.auth import get_user_model
from cuser.forms import UserCreationForm
from .forms import CustomUserChangeForm
class CustomUserAdmin(admin.OSMGeoAdmin):
model = get_user_model()
add_form = UserCreationForm
form = CustomUserChangeForm
list_display = ['email', 'last_name', 'first_name']
readonly_fields = ['last_login', 'date_joined']
def get_form(self, request, obj=None, **kwargs):
"""
Use special form during user creation.
Override get_form method in the same manner as django.contrib.auth.admin.UserAdmin does.
"""
defaults = {}
if obj is None:
defaults['form'] = self.add_form
defaults.update(kwargs)
return super().get_form(request, obj, **defaults)
admin.site.register(get_user_model(), CustomUserAdmin)

Django rest framework Custom User model with token error

I've tried to use custom user model instead of default user.
My Django project structure is below.
Project name : project_rest
App name : app_rest
To make it happen, I refer https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#substituting-a-custom-user-model
[settings.py]
AUTH_USER_MODEL = 'app_rest.User'
[models.py]
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
from django.conf import settings
from django.contrib.auth.models import AbstractUser
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
class User(AbstractUser):
username = models.CharField(unique=True, null=False, max_length=254)
password = models.CharField(max_length=200)
[serializers.py]
from app_rest.models import User
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username', 'password')
[views.py]
from django.shortcuts import render
from app_rest.serializers import UserSerializer
from app_rest.models import User
from rest_framework import viewsets
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
[urls.py]
from django.conf.urls import url, include
from app_rest import views
from rest_framework import routers
from django.contrib import admin
from rest_framework.authtoken import views as rest_views
router = routers.DefaultRouter()
router.register(r'user', views.UserViewSet)
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^token-auth/', rest_views.obtain_auth_token),
url(r'^admin/', admin.site.urls),
]
I seems work properly, But when I delete user, It throws error.
IntegrityError at /admin/app_rest/user/1/delete/ (1452, 'Cannot add or
update a child row: a foreign key constraint fails
('rest'.'django_admin_log', CONSTRAINT
'django_admin_log_user_id_c564eba6_fk_auth_user_id' FOREIGN KEY
('user_id') REFERENCES 'auth_user' ('id'))')
How can I solve this issue?
The error is pretty self explanatory. The record you are trying to delete is related to another one by a foreign key and it cannot be deleted as it would break referential integrity.
You need to alter that id with something like ON DELETE CASCADE or its equivalent, or allow the user to be null on the related table (if that's possible).

django profile creation, set User profile while using multiple profile types

I am stuck at user registration, I actually intends to have different profile types. While registration I am unable to set UserProfile while creating a user. I am using UserCreationForm. code in my files are as following.
from django.contrib.auth.forms import UserCreationForm
from registration.forms import RegistrationForm
from django import forms
from django.contrib.auth.models import User
from accounts.models import UserProfile
from django.utils.translation import ugettext_lazy as _
from person.models import Person
from pprint import pprint
class UserRegistrationForm(UserCreationForm):
#email = forms.EmailField(label = "Email")
fullname = forms.CharField(label = "Full name")
class Meta:
model = User
fields = ("email","fullname","password1","password2" )
def __init__(self, *args, **kwargs):
super(UserRegistrationForm, self).__init__(*args, **kwargs)
del self.fields['username']
def clean_email(self):
"""
Validate that the supplied email address is unique for the
site.
"""
if User.objects.filter(email__iexact=self.cleaned_data['email']):
raise forms.ValidationError(_("This email address is already in use. Please supply a different email address."))
return self.cleaned_data['email']
def save(self, commit=True):
user = super(UserRegistrationForm, self).save(commit=False)
#user_profile=user.set_profile(profile_type="Person")
UserProfile.profile.person.full_name = self.cleaned_data["fullname"]
user.email = self.cleaned_data["email"]
if commit:
user.save()
return user
class CompanyRegistrationForm(UserCreationForm):
email=forms.EmailField(label="Email")
class UserProfileForm(forms.ModelForm):
class Meta:
model=UserProfile
exclude=('user',)
accounts/models.py
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user=models.OneToOneField(User)
meta_keywords=models.CharField("Meta Keywords",max_length=255,
help_text="Comma delimited set of keywords of meta tag")
meta_description=models.CharField("Meta Description",max_length=255,
help_text='Content for description meta tag')
def __unicode__(self):
return "User Profile for: "+self.username
class Meta:
ordering=['-id']
views.py
from django.contrib.auth.forms import UserCreationForm
from django.template import RequestContext
from django.shortcuts import render_to_response,get_object_or_404
from django.core import urlresolvers
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from accounts.forms import UserRegistrationForm, UserProfileForm
#from accounts.forms import UserProfile
def register(request,template_name="account/register.html"):
if request.method=='POST':
postdata=request.POST.copy()
form=UserRegistrationForm(postdata)
user_profile=UserProfileForm(postdata)
if form.is_valid():
form.save()
un=postdata.get('username','')
pw=postdata.get('password','')
from django.contrib.auth import login,authenticate
new_user=authenticate(username=un,password=pw)
if new_user and new_user.is_active:
login(request,new_user)
url=urlresolvers.reverse('dashboard')
return HttpResponseRedirect(url)
else:
form=UserRegistrationForm()
page_title="User Registration"
return render_to_response(template_name,locals(),context_instance=RequestContext(request))
#login_required
def dashboard(request):
pass
#login_required
def settings(request):
pass
As I am using multiple profiles so following is code of one of those profiles' models.py:
from django.db import models
from django.contrib.auth.models import User
from accounts.models import UserProfile
class Person(UserProfile):
skills=models.CharField(max_length=100)
fullname=models.CharField(max_length=50)
short_description=models.CharField(max_length=255)
is_online=models.BooleanField(default=False)
tags=models.CharField(max_length=50)
profile_pic=models.ImageField(upload_to="person_profile_images/")
profile_url=models.URLField()
date_of_birth=models.DateField()
is_student=models.BooleanField(default=False)
current_designation=models.CharField(max_length=50)
is_active_jobseeker=models.BooleanField(default=True)
current_education=models.BooleanField(default=True)
class Meta:
db_table='person'
My profile auth in settings.py
AUTH_PROFILE_MODULE='accounts.UserProfile'
Here is a file that also I used after looking at some other place, profile.py:
from accounts.models import UserProfile
from accounts.forms import UserProfileForm
from person.models import Person
from company.models import Company
def retrieve(request,profile_type):
try:
profile=request.user.get_profile()
except UserProfile.DoesNotExist:
if profile_type=='Person':
profile=Person.objects.create(user=request.user)
else:
profile=Company.objects.create(user=request.user)
profile.save()
return profile
def set(request,profile_type):
profile=retrieve(request,profile_type)
profile_form=UserProfileForm(request.POST,instance=profile)
profile_form.save()
I am new and confuse, have seen documentation also. Also saw other solutions at stackoverflow.com but didn't find any solution of my problem. So please tell if you find anything helpful for me. It doesn't seems to be a big problem but as I am new to it so it is a problem for me.
Multiple profile types won't work with the OneToOne relation that is required by Django profile mechanism. I suggest you keep a single profile class containing data common to all profile types and you store type-specific data in a separate set of classes that you link to your profile class using a generic relation.
EDIT:
Thanks for the clarification. Looking at your code again today it seems that you might indeed be able to accomplish what your trying to do with model inheritance. I think the problem is in the save() method of UserRegistrationForm. Try something like this:
def save(self, commit=True):
user = super(UserRegistrationForm, self).save(commit=False)
user.email = self.cleaned_data["email"]
if commit:
user.save()
person = Person(user=user)
person.full_name = self.cleaned_data["fullname"]
person.save()
return user