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.
Related
on a Django project that uses django-taggit (https://pypi.org/project/django-taggit/)
I would like to make tags on a per user basis, this way each user can define its own set of tags.
I'm settings up the following model:
# models.py
from django.db import models
from taggit.models import Tag
from django.contrib.auth.models import User
# Create your models here.
class MyTag(Tag):
""" You must make taggit.models.Tag an abstract model"""
user = models.ForeignKey(User, related_name="to_tags", on_delete=models.SET_NULL)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def save(self, args, kwargs):
user = kwargs.pop('user')
self.user = user
super(MyTag, self).save(*args, **kwargs)
then to manage I'd use a normal form ( in this case the tags are for a Photo model)
# forms.py
class PhotoForm(forms.ModelForm):
class Meta:
model = Photo
fields = ('name', 'artistic_name', 'description', 'tags', 'is_top', 'note')
widgets = {
'description': forms.Textarea(attrs={'rows': 2}),
'note': forms.Textarea(attrs={'rows': 2})
}
now the Question...how to I save the user in the MyTag model?
I have to pass it to the form instance in the view doing something like:
def photo_detail(request, photo_id):
...
form = PhotoForm(request.POST or None, user=request.user)
...
if request.method == 'POST':
if form.is_valid():
form.save()
...
first question...should I pass the user when I make the form instance, or when I call the save method...?
Then I would have to intercept the Tag.save()...but here I'm lost.
Any help is appreciated.
Thank you very much!
Carlo
I'm trying to make some forms that will allow users to add some objects, delete them or edit but I've stucked with thing like author of model. Let's say we got model Shot which got field
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
Because I've created custom user model to expand user by some fields that I want, and then we creating modelForm, creating views etc. and finally got form. When we will try to submit this form, it won't add this object submited in form to db because form has no filled field author author which means this field == Null and that's why it won't add this to db. So my question is how to get it dynamic, for example when user with nick "thebestuser" will try to add this modelForm it will work and mark author as "thebestuser"? Ofc I could add to form field author, but it's the worst way in my opinion and every user would be allowed then to add object for example as a another user, let's say user with nick "anothernick" could add form as a user with "thebestuser" which is In my opinion not acceptable.
models.py
from django.db import models
from django.contrib.auth.models import User
from streamers.models import Streamer
from django.conf import settings
from django.utils import timezone
class Shot(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=70)
url = models.CharField(max_length=100)
streamer = models.ForeignKey(Streamer, on_delete=models.CASCADE)
published_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
forms.py
from django import forms
from .models import Shot
class AddShot(forms.ModelForm):
class Meta:
model = Shot
fields = [
'title',
'url',
'streamer',
]
views.py
#login_required
def add_shot(request):
form = AddShot(request.POST or None)
if form.is_valid():
form.save()
instance = form.save(commit=False)
instance.published_date = request.published_date
instance.author = request.user
instance.save()
context = {
'form': form
}
return render(request, 'shots/add_shot.html', context)
You'll need to do it in your view. When you save your form pass commit=False to your save method, add your user, then save the returned instance.
def my_view(request):
form = AddShot(request.POST)
instance = form.save(commit=False)
instance.author = request.user
instance.save()
Documented here: https://docs.djangoproject.com/en/2.1/topics/forms/modelforms/#the-save-method
I have a registration form for an event. Since this registration form displays as a modal when clicking the 'Register' button on the event page, I know what event it is that the user want to register to. But Django doesn't, since I don't know how to implement this in code.
I have two models: Participant and Event. Each instance of Participant refers to an Event instance by means of ForeignKey. How do I set that ForeignKey depending on the slug of the event page?
This is my code example:
models.py:
from django.db import models
class Event(models.Model):
name = models.CharField(max_length=50)
description = models.CharField(max_length=500)
#<...>
slug = models.SlugField()
class Participant(models.Model):
name = models.CharField(max_length=200)
email = models.EmailField()
event = models.ForeignKey(Event, on_delete=models.CASCADE)
forms.py:
from django.forms import ModelForm
from .models import Participant
class ParticipantForm(ModelForm):
class Meta:
model = Participant
fields = ['name', 'email']
views.py:
from django.template.loader import render_to_string
from django.views import generic
from .models import *
from .forms import *
class RegistrationView(generic.FormView):
template_name = 'me/registration.html'
form_class = ParticipantForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['event'] = Event.objects.get(slug=self.args[0])
return context
def form_valid(self, form):
form.save()
return HttpResponse(render_to_string('me/registration-complete.html', {'event': Event.objects.get(slug=self.args[0])}))
You'd need to set it in form_valid. In this circumstance get_context_data wouldn't have been called, so you need to get the event again; you might want to extract that into a separate method.
def form_valid(self, form):
form.instance.event = Event.objects.get(reference_name=self.args[0])
form.save()
return ...
models.py
from django.db import models
from accounts.models import User
# Create your models here.
class Customer(models.Model):
user_customer = models.OneToOneField(User)
customer_name = models.CharField(max_length=100,blank=True)
phone_no = models.CharField(max_length=100,blank=True)
inserted = models.DateTimeField(auto_now_add=True,null=True,blank=True)
created = models.DateTimeField(auto_now=True,)
views.py
from django.shortcuts import render,redirect
from django.views.generic.edit import CreateView
from accounts.models import User
from accounts.forms import RegisterForm
from .forms import CustomerRegistration
from .models import Customer
def CustomerSignupView(request):
r_form = RegisterForm(request.POST or None)
c_form = CustomerRegistration(request.POST or None)
context = {
"r_form":r_form ,
"c_form":c_form ,
}
if r_form.is_valid() and c_form.is_valid():
instance = r_form.save(commit=False)
instance.is_customer = True
instance.save()
c_form.save()
return redirect("/")
return render(request,"customerregister.html",context)
forms.py
from django import forms
from .models import Customer
class CustomerRegistration(forms.ModelForm):
class Meta:
model = Customer
fields = ('customer_name','phone_no',)
I have two separate forms - RegisterationForm(RF) and CustomerRegistrationForm(CRF).
CRF inherits RF, I want to save two forms in single view i.e.CustomerSignupView.
While submitting the forms Intergrity error pops up, and the data saved is only from RegistrationForm.
How do I save both forms in thier respective table with integrity maintained.
Thanks.
You haven't shown your forms, but it looks as if you have to set the user before you save the customer to the database:
if r_form.is_valid() and c_form.is_valid():
instance = r_form.save(commit=False)
instance.is_customer = True
instance.save()
customer = c_form.save(commit=False)
customer.user_customer = instance
customer.save()
return redirect("/")
You have to create a User from accounts.models before creating you Customer, if your r_form is a instance of User your c_form will fail because user is required to c_form be valid
if r_form.is_valid():
instance = r_form.save(commit=False)
instance.is_customer = True
instance.save()
if c_form.is_valid():
customer = c_form.save(commit=False)
customer.user_customer = instance
customer.save()
return redirect("/")
Suggestion: why you not Inherite User to your Customer since your Customer is once User
from accounts.models import User
class Costumer(User):
...
This way you can setup the Costumer and User in just one form, is easy to acess the data from Costumer.
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)