how to render two forms in one template using a class based view - django-views

I'm using django's built-in User model, but I also have my own Account model which extends it:
class Account(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
age = models.IntegerField(blank=True)
location = models.CharField(max_length=255, blank=True)
experience = models.TextField(blank=True)
in my admin.py file:
class AccountInline(admin.StackedInline):
model = Account
can_delete = False
verbose_name_plural = 'Accounts'
class CustomUserAdmin(UserAdmin):
inlines = (AccountInline,)
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
I want it to be that when a User registers they enter this information in, but my issue is getting both the UserForm and AccountForm in the same template/view.
As of now this is my registration view:
class UserRegistration(generic.CreateView):
form_class = RegisterForm
template_name = 'registration/registration.html'
def form_valid(self, form):
user = form.save()
form.registration_notification()
login(self.request, user, backend='django.contrib.auth.backends.ModelBackend')
return redirect(self.request.GET.get('next'))
How do I add my AccountForm to this view as well so that I can render both in the template and submit with one button. I've seen people do it with a function based view but is there a way to do it with a class-based view?
I also want the same idea for my UpdateView where a User can update User information, but also Account information. I assume it would follow the same logic.

You can use a Custom user model "Extend AbstractUser" since you want to add extra fields and add as many other fields as you want in a single model and avoid making extra queries to the database.
From Django documentation :
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
field 1
field 2
forms.py
from django.contrib.auth.forms import UserCreationForm
from myapp.models import User
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = User
fields = UserCreationForm.Meta.fields + ('custom_field',)
You can read more here

Related

Serialise an extended User Model in Django

I'm extending a django auth user model in a Profile model:
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
activity = models.IntegerField(default=500)
def _str_(self):
return self
in my views I'm getting the current auth user and I get the associated profile:
#api_view(['GET'])
#permission_classes([IsAuthenticated])
def getUserProfile(request):
profile = Profile.objects.get(user = request.user)
serializer = profileSerializer(profile, many=False)
return Response(serializer.data)
Here is my serializers code:
from rest_framework import serializers
from .models import Profile
class profileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ('first_name', 'activity')
The error I'm getting that Profie object has not a first_name attribute, but when I replace 'first_name' with 'user' I get only the id of the user, so I want to show the first_name as well.
Thank you
The OneToOneField connects your field user in the Profile model to a User object which has a first_name attribute, but in the Profile table that user field is just a number that says which User object it is. To access the first name, you can do this:
from rest_framework import serializers
from .models import Profile
class profileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = '__all__'
Then in your template you could display the first_name like this, assuming you pass person to it where person is an instance of the Profile model:
{{ person.user.first_name }}
I also think it would be less confusing to use another name for the field, rather then user. Call it person maybe, like:
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
person = models.OneToOneField(User, on_delete=models.CASCADE)
activity = models.IntegerField(default=500)
def _str_(self):
return self
Try this:
from django.contrib.auth.models import User
class profileSerializer(serializers.ModelSerializer):
first_name = serializers.CharField(max_length=200, read_only=True)
class Meta:
model = Profile
fields = ('user', 'first_name', 'activity')
def get_first_name(self, obj):
return User.objects.filter(id=obj.user.id).first().values_list('first_name', flat=True).last()
I was able to show the fields I wanted using Django depth in the serializer
from rest_framework import serializers
from .models import Profile
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('first_name', 'last_name')
class profileSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Profile
fields = ('activity','user')
depth=1

In Django, how to add username to a Model automatically, when the Form is submitted by a logged in user

In my Django app, I have defined a Many-to-one relationship using ForeignKey. Now what I want is that when a logged-in user submits the ListForm then his username should automatically add to the owner field of the ListModel. Currently when a user submits the form, None is being shown in the owner field, how can I add the username to the database along with the form?
my models.py:
from django.db import models
from django.contrib.auth.models import User
class ListModel(models.Model):
owner = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE)
task = models.CharField(max_length=255)
completed = models.BooleanField(default=False)
my forms.py:
from django.forms import ModelForm
from .models import ListModel
from django import forms
class ListForm(ModelForm):
class Meta:
model = ListModel
fields = ['owner','task', 'completed']
You have to override the form_valid() method of the View and attach the current logged in user as an Owner.
def form_valid(self, form):
form.instance.owner = self.request.user <------ This line will do the trick.
return super().form_valid(form)
Finally got it working (my solution reference)
First, we need to exclude the owner field from the ModelForm in forms.py:
class ListForm(ModelForm):
class Meta:
model = ListModel
fields = ['task', 'completed']
# instead of above line we can simply write: exclude = ['owner']
and in the views.py:
form = ListForm(request.POST)
if form.is_valid():
task_list = form.save(commit=False)
task_list.owner = request.user
task_list.save()
return redirect('/')
where instead of task_list we can use any variable & also note that after task_list.save() no need to do form.save() because it's already included in task_list = form.save(commit=False)

Django forms dynamic getting author as a logged in user in model forms

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

UserProfile db showing (None) in django

I was dealing with user authentication in django and created a UserProfile model with foreign key to User in-built model. Then I created explicitly defined User model and then deleted it to restore the original code.
But now in my UserProfile database accessed from admin page is showing (None) for all the profiles created earlier.
And when I click on it it shows an error.
This is the code:
forms.py and models.py
from django import forms
from django.contrib.auth.models import User
from cms.models import UserProfile
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ('username', 'email', 'password')
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('designation',)
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
designation = models.CharField(max_length=128,blank=True)
def __unicode__(self):
return self.user.username
How do I delete that (None)?
As I said in comments, it's because your __unicode__() built-in method prints this user
Try change this part of the code to:
def __unicode__(self):
try:
return self.user.username
except:
return "UserProfile has No User instance"

How to extend UserCreationForm with fields from UserProfile

I found this post on how to extend the UserCreationForm with extra fields such as "email." However, the email field is already defined in the pre-built user model.
I created an extra model (called UserProfile) that futher extends Django's pre-built User class. How do I get these fields I defined in UserProfile to appear in my UserCreationForm?
Add fields as appropriate for your UserProfile model (it's not too easy to use a ModelForm to avoid Repeating Yourself, unfortunately), then create and save a new UserProfile instance in the over-ridden save() function. Adapted from the post you linked to:
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class UserCreateForm(UserCreationForm):
job_title = forms.CharField(max_length=100, required=True)
age = forms.IntegerField(required=True)
class Meta:
model = User
def save(self, commit=True):
if not commit:
raise NotImplementedError("Can't create User and UserProfile without database save")
user = super(UserCreateForm, self).save(commit=True)
user_profile = UserProfile(user=user, job_title=self.cleaned_data['job_title'],
age=self.cleaned_data['age'])
user_profile.save()
return user, user_profile