Ok, so I've built a basic Django Project and successfuly installed the django-registration app - http://www.michelepasin.org/blog/2011/01/14/setting-up-django-registration/
I want to expand a User to include information like Birthday, Profile Picture etc. I created an app called user_profile. This is the signals.py inside the registration app:
from django.dispatch import Signal
user_activated = Signal(providing_args=["user", "request"])
From inside my new app, user_profile, what is the way to listen for this signal? I think I should create a signals.py file, but what should I write inside? a from registration.signals import user_activated statement and what else? This new app which I've created also has a model.py which I want to automatically populate with some data when a new account has been activated.
And another secondary question: when I link a URL with a class based view, which method of that class is triggered? If I have 4 methods inside inside the class based view, how django decides which one to use? Thanks
OKay, if I understand your problem, you'll have put something like this at the end of your user_profile/models.py file :
from django.contrib.auth.models import User
from django.db.models.signals import post_save
def create_user_profile(sender, instance, **kwargs):
"""
Function to create user profile.
sender is the model class that sends the signal,
while instance is an actual instance of that class
"""
# your own logic here, for example :
user = instance
profile = UserProfile()
profile.user = user # link the profile to the user
profile.save()
# connect the function to the signal, for User instances)
post_save.connect(create_user_profile, sender=User)
For your second question, many methods are called during class based views execution. In order to use class based views, your URLconf should look like this :
from myapp import views
from django.conf.urls import patterns, url
urlpatterns = patterns('',
url(r'list_something', views.YourListView.as_view(), name="list_something"),
)
But you should not override as_view() method in your view. Depending on what you're trying to do, you'll have other methods to overwrite. I can maybe help you if you provide more info.
Thanks Eliot, here is what I have so far:
signals.py is now removed.
models.py:
import datime
from django.db import models
from django.contrib.auth.models import User
try:
from django.utils.timezone import now as datetime_now
except ImportError:
datetime_now = datetime.datetime.now
class UserProfileManager(models.Manager):
def create_user_profile(self, user):
user_profile = self.create(user = user)
return user_profile
class UserProfile(models.Model):
YEARS = tuple(zip(range(1900, datetime_now.year)), zip(range(1900, datetime_now.year)))
MONTHS = (
('January','January'),('February','February'),('March','March'),('April','April'),
('May','May'), ('June','June'),('July','July'),('August','August'),
('September','September'),('October','October'),('November','November'), ('December', 'December')
)
GENDERS = (('M', 'Male'), ('F', 'Female'))
user = models.ForeignKey(User, unique=True, verbose_name=_('user'))
birthday_year = models.CharField(max_length=1, blank = True, null = True, choices=YEARS)
birthday_month = models.CharField(max_length=1, blank = True, null = True, choices=MONTHS)
gender = models.CharField(max_length=1, blank = True, null = True, choices=GENDERS)
creation_time = models.DateTimeField(auto_now_add = True, auto_now = False)
update_time = models.DateTimeField(auto_now_add = False, auto_now = True)
class Meta:
verbose_name = _('user profile')
verbose_name_plural = _('user profiles')
objects = UserProfileManager()
def create_user_profile(sender, instance, **kwargs):
profile = UserProfile.objects.create_user_profile(user=instance)
profile.save()
post_save.connect(create_user_profile, sender=User)
Related
I want to create an entry on UserExtended model after registering an user on Django default user model.
here is UserExtended model:
class UserExtended(models.Model):
extended_id = models.AutoField(primary_key=True, editable=False)
avatar = models.ImageField(null=True, blank=True, default='Capture.PNG')
user = models.OneToOneField(User, on_delete=models.CASCADE, null=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
here is the view function that registering the user
#api_view(['POST'])
def register_user(request):
data = request.data
user = User.objects.create(
first_name=data['name'],
username=data['username'],
email=data['email'],
password=make_password(data['password'])
)
serializer = UserSerializerWithToken(user, many=False)
return Response(serializer.data)
here is the serializer
class UserSerializer(serializers.ModelSerializer):
name = serializers.SerializerMethodField(read_only=True)
isAdmin = serializers.SerializerMethodField(read_only=True)
avatar = serializers.SerializerMethodField()
def get_avatar(self, obj):
avatar = obj.userextended.avatar.url
print(avatar)
if avatar == '':
avatar = 'null'
return avatar
class Meta:
model = User
fields = ['id', 'username', 'email', 'name', 'avatar', 'isAdmin']
def get_name(self, obj):
name = obj.first_name
if name == '':
name = obj.email
return name
def get_isAdmin(self, obj):
return obj.is_staff
class UserSerializerWithToken(UserSerializer):
token = serializers.SerializerMethodField(read_only=True)
class Meta:
model = User
fields = ['id', 'username', 'email', 'name', 'isAdmin', 'token']
here is the signal.py:
from django.db.models.signals import post_save, pre_delete
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import UserExtended
#receiver(post_save, sender=User)
def create_user_extended(sender, instance, created, **kwargs):
if created:
UserExtended.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_extended(sender, instance, **kwargs):
instance.userextended.save()
but the signal is not working to create an default avatar file for an new registered user
I am new. Please help me.
Django does not look for any file named signal.py, etc. by default. Hence what is happening it that your signals are never registered (in fact the file you write them in is never run). The general solution to adding signals is to write them in a separate file and then import / register them in the app config's ready method.
In the app in which you write signal.py there should be a file apps.py in which there should be a class inheriting from AppConfig edit this class and add a ready method to it and import your signals there:
from django.apps import AppConfig
# The parts marked as "Don't edit" mean to keep them as it already is in _your_ code and not copy it
class YourAppConfig(AppConfig): # Don't edit
default_auto_field = 'django.db.models.BigAutoField' # Don't edit
name = 'your_app' # Don't edit
# Copy only the code below
def ready(self):
# models, signals etc. are imported only here because otherwise the models might not be loaded yet
from . import signal
Hello I am a newbie and have a task to do,I have tried simple social authentication that is working but below is bit complicated:
Create a social authentication functionality with google and add user in a
database. After adding user in a database, customer should also be created
using django signals.
Note:- Customer is one to one related with user?
My models.py :
class Buddy(models.Model):
user_name=models.CharField(max_length=200,blank=True,null=True)
def __str__(self):
return str(self.user_name)
class Customer(models.Model):
customer_name=models.OneToOneField(Buddy,
on_delete = models.CASCADE,
blank=True,null=True)
def __str__(self):
return str(self.customer_name)
My settings.py includes the following lines:
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = '2377[...].apps.googleusercontent.com'
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = '[...]'
SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = ['email']
INSTALLED_APPS = [ ... # oauth
'oauth2_provider',
'social_django',
'rest_framework_social_oauth2' ]
AUTHENTICATION_BACKENDS = ( # Google OAuth2
'social_core.backends.google.GoogleOAuth2',
# django-rest-framework-social-oauth2
'rest_framework_social_oauth2.backends.DjangoOAuth2', # Django
'django.contrib.auth.backends.ModelBackend', )
You have to use Django's post_save signal.
In your models.py have:
class Buddy(models.Model):
user_name=models.CharField(max_length=200, blank=True, null=True)
def __str__(self):
return str(self.user_name)
class Customer(models.Model):
# This translates into buddy_id when you migrate
buddy=models.OneToOneField(Buddy,on_delete = models.CASCADE,
blank=True, null=True)
customer_name = models.CharField(max_length=200, blank=True, null=True)
def __str__(self):
return str(self.customer_name)
In your views.py make sure you have
from django.shortcuts import render
from django.db.models.signals import post_save
from .models import Buddy
from .callbacks import save_customer
# You'll customize this view to read any parameters and provide user_name
def custom_view(request):
Buddy.objects.create(user_name="SomeUsername")
# Any of your other logic comes here, specify in the dict
return render(request, 'yourpage.html', {})
# This should be at the bottom of your views.py:
post_save.connect(save_customer, sender=Buddy)
Then create a new file in the same location called callbacks.py and there include:
from .models import Buddy
from django.db.models.signals import post_save
from django.dispatch import receiver
#receiver(post_save, sender=Buddy)
def save_customer(sender, instance, **kwargs):
# Customize your OneOnOne model on a meaningful way so it will be useful
customer = Customer.objects.create(customer_name=instance.user_name)
instance.customer = customer
instance.customer.save()
Read more about Django signals here.
I have exhausted all avenues in trying to put together a solution for this, but my current knowledge of Python and Django can only get me so far.
I'm creating a basic ticketing system and CreateView used to work until I created a Profile model and then separated the Ticket model into its own app. There were already a couple of tickets created when I refactored my code which is why I know ListView works, DeleteView works as well as DetailView. CreateView works until I hit the save button.
My views and models are below; I hope someone can please help me sort this out.
Ticket Model
from django.db import models
from django.contrib.auth.models import User
....
from qcapp.models import Profile
class Ticket(models.Model):
# Relations
user = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name="tickets", verbose_name="user")
# Attributes
title = models.CharField(max_length=250, verbose_name="Title", help_text="Enter a Ticket Title")
color = models.CharField(max_length=7,
default="#ffffff",
validators=[RegexValidator("(^#[0-9a-fA-F]{3}$)|(^#[0-9a-fA-F]{6}$)")],
verbose_name="Color",
help_text="Enter the hex color code, like #ccc or #cccccc")
description = models.TextField(max_length=1000)
created_date = models.DateTimeField(default=timezone.now, verbose_name='Created Date')
created_by = models.ForeignKey(User, related_name='created_by_user')
# Attributes
# Object Manager
objects = managers.ProjectManager()
# Meta and String
class Meta:
verbose_name = "Ticket"
verbose_name_plural = "Tickets"
ordering = ("user", "title")
unique_together = ("user", "title")
def __str__(self):
return "%s - %s" % (self.user, self.title)
def get_absolute_url(self):
return reverse('ticket_detail', args=[str(self.id)])
Ticket View (CreateView Only)
# -*- coding: utf-8 -*-
...
from django.views.generic import CreateView, UpdateView, DeleteView
...
from .models import Ticket
...
class TicketCreate(CreateView):
model = Ticket
template_name = "tickets/ticket_form.html"
fields = ['title', 'description']
def form_valid(self, form):
form.instance.created_by = self.request.user
return super(TicketCreate, self).form_valid(form)
...
Profile Model(Imported Into Ticket Model)
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
from django.dispatch import receiver
from django.db.models.signals import post_save
from . import managers
class Profile(models.Model):
# Relations
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="profile", verbose_name="user")
# Attributes
interaction = models.PositiveIntegerField(default=0, verbose_name="interaction")
# Attributes
# Object Manager
objects = managers.ProfileManager()
# Custom Properties
#property
def username(self):
return self.user.username
# Methods
# Meta and String
class Meta:
verbose_name = "Profile"
verbose_name_plural = "Profiles"
ordering = ("user",)
def __str__(self):
return self.user.username
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_for_new_user(sender, created, instance, **kwargs):
if created:
profile = Profile(user=instance)
profile.save()
It looks like you need to add the following to your TicketCreate class in the form_valid function:
form.instance.user = Profile.objects.get(user=self.request.user)
Let me know if that works!
How can I populate the following tables with some default / initial data, every-time new user is created ? I know about this https://docs.djangoproject.com/en/dev/howto/initial-data/, but this works only when I create models. Here I want to insert some default entries when new user is created.
Additionally, when I create a new user how can I add him to a given group with a static group id automatically ?
models.py
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=50)
user = models.ForeignKey(User)
class Feed(models.Model):
url = models.URLField()
name = models.CharField(max_length=50)
created = models.DateTimeField(auto_now_add=True)
description = models.TextField(blank=True)
category = models.ForeignKey(Category)
user = models.ForeignKey(User)
views.py
def signup(request):
if request.method == 'POST':
form = UserCreationForm1(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect("/accounts/login")
else:
form = UserCreationForm1()
return render(request, "registration/signup.html", {
'form': form,
})
forms.py
class UserCreationForm1(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ('username', 'email')
Many thanks!
What you're looking for is Django's signals framework.
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User, Group
from my_app import Category, Feed
#receiver(post_save, sender=User)
def init_new_user(instance, created, raw, **kwargs):
# raw is set when model is created from loaddata.
if created and not raw:
instance.groups.add(
Group.objects.get(name='new-user-group'))
Category.objects.create(
name="Default", user=instance)
Feed.objects.create(
user = instance,
name = "%s's Feed" % instance.first_name,
....
)
REF: https://docs.djangoproject.com/en/1.5/topics/signals/
There are at least two ways you can handle populating additional models with data when creating a new user. This first one that comes to mind is a post_save signal:
from django.db.models.signals import post_save
from django.dispatch import receiver
from your_app.models import Category, Feed
#receiver([post_save, post_delete], sender=Coupon)
def add_user_data(sender, **kwargs):
user = kwargs.get('instance')
try:
category, category_created = Category.objects.get_or_create(user=user,
defaults={'name': 'Some Value', 'user': user})
try:
feed, feed_Created = Feed.objects.get_or_create(user=user,
category=category, defaults={'url': 'some-url',
'name': 'some-name', 'description': 'some-desc',
'category': category, 'user': user})
except MultipleObjectsReturned:
pass
except MultipleObjectsReturned:
pass
This code would execute any time an instance of User is saved, but only create the additional records if they don't already exist for that user.
Another way would be to override the save() method on a form for the User. If you also need this functionality in Django admin, you would need to un-register the built-in UserAdmin and register your own UserAdmin class to leverage the custom form.
I am learning django. Right now, I need to create a Userprofile.
I already created the model which is
class UserProfile(models.Model):
user = models.OneToOneField(User)
active = models.BooleanField()
address = models.CharField('Shipping address', max_length=150, blank=True, null=True)
telephone = models.CharField('Telephone number for shipping', max_length=20, blank=True, null=True)
steps = models.DecimalField('Steps since creation', max_digits=100, decimal_places=2, null=True)
active = models.BooleanField()
def __str__(self):
return "%s's profile" % self.user
inside an application called accounting. I already created
def create_user_profile(sender, **kwargs):
#When creating a new user, make a profile for him or her.
u = kwargs["instance"]
if not UserProfile.objects.filter(user=u):
UserProfile(user=u).save()
post_save.connect(create_user_profile, sender=User)
So every time a user is created, a profile created automatically. I've already created and verified that the user was created in userprofile table. I also went the shell. I looked for that user which ID is 4. I printed adress for User 4 and I got the address. So I am sure they are linked and working. But when I go to the HTML, i get the error.
Here is the View.
from accounting.models import UserProfile, Charge, Wallet
from django.shortcuts import get_object_or_404, RequestContext
from django.shortcuts import render_to_response
from django.http import HttpResponse
from django.template import Context, loader
from django.contrib.auth.forms import UserCreationForm
#def userprofile(request, user_id):
def userprofile(request, user_id):
user_profile = request.user.get_profile()
active = user_profile.active
return render_to_response('accounting/templates/userprofile.html', {
'user_profile': user_profile,
'active': active,
}, context_instance=RequestContext(request))
Thanks.
Make sure you have set AUTH_PROFILE_MODULE = 'my_profile_app.UserProfile' in settings.py
Instead of:
request.user.get_profile()
Use:
request.user.userprofile
After years of Django development, never needed AUTH_PROFILE_MODULE or get_profile(). I don't know what's the advantage of using get_profile() (if any) but it seems like un-needed hassle.
Actually, I go through even less hassle by using django-annoying's AutoOneToOneField: https://bitbucket.org/offline/django-annoying/wiki/Home
More about OneToOne: https://docs.djangoproject.com/en/dev/topics/db/models/#one-to-one-relationships