So i've been working on a project for a while, in which I use the Django default User Instance but with additional attributes, which are stored in a "Profile"-Model. So right now i have an assigned company, and an Profile-Image for the user in the Profile Model.
Now i have a detailview to edit the user's attributes (firstname, username, email, etc.). i used generic.DetailView for this View. But this is only working for the Attributes in the User-Model from Django. How can I also change Attributes in the Profile Model when editing the User?
This is my Edit-View:
class ProfileUpdateView(LoginRequiredMixin, UpdateView):
model = User
fields = ['username', 'email', 'first_name', 'last_name']
template_name = 'inventory/edit_forms/update_profile.html'
success_url = '/profile'
login_url = '/accounts/login'
redirect_field_name = 'redirect_to'
def form_valid(self, form):
profile = Profile.objects.get(user=self.request.user)
profile.img = self.request.POST.get('profile_img')
profile.save()
return super().form_valid(form)
def get_object(self):
return User.objects.get(pk = self.request.user.id)
This is my HTML:
<form class="edit_object" action="" method="post" enctype='multipart/form-data' class="form-group">
<div style="width: 20%; margin-bottom: 1rem;">
<label>Profile Image</label>
<input name="profile_img" type="file" accept="image/png, image/gif, image/jpeg">
</div>
{% csrf_token %}
{{form|crispy}}
<input type="submit" value="Submit" class="btn action_btn">
</form>
As you see i already tried using a external Input field and setting the image like that. But after submitting, the img attribute in the Profile-Model is just set null and I don't know why.
What did I miss?
if you want to go this way use request. FILES
So my form was working just fine until i played around with my frontend...changing the look of the system. But i dont think this has an effect on my forms but surprisingly all my forms are no longer saving data to the database!!
Some help here guys.
Here is my views.py
from django.contrib.auth.models import User
from django.contrib import messages
from django.shortcuts import render, redirect
from django.contrib.auth import login, authenticate
from .forms import *
# Create your views here.
def register(request):
form = RegistrationForm()
if request.method == "POST":
form = RegistrationForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'User successfully registered!')
return redirect('home')
else:
form = RegistrationForm()
return render(request, 'accounts/register.html', {'form': form} )
def login(request):
if request.method == 'POST':
username = username.POST['username']
password = request.POST['password']
try:
user = Account.objects.get(username=username)
except:
messages.error(request, 'username does not exist')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('home')
else:
messages.error(request, 'Invalid username Or Password')
return render(request, 'accounts/login.html', {} )
models.py
from distutils.command.upload import upload
import email
from django.db import models
from django.conf import settings
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.base_user import BaseUserManager
class MyAccountManager(BaseUserManager):
def _create_user(self, email, username, profile_pic, address, phone_number, car, details, password):
if not email:
raise ValueError("User must have an email")
if not username:
raise ValueError("User must have a username")
user = self.model(
email = self.normalize_email(email),
username = username, profile_pic=profile_pic, address = address,
phone_number = phone_number, car=car, details=details, password=password
)
user.set_password(password)
user.save(using=self._db)
return user
def create_user(self, email, username, profile_pic=None, address=None, phone_number=None, car=None, details=None, password=None):
return self._create_user(email, username, profile_pic, address, phone_number, car, details, password)
def create_superuser(self, email, username, password):
"""
Creates and saves a superuser with the given email, name and password.
"""
user = self.create_user(email=email,
username=username,
password=password,
)
user.is_admin = True
user.is_superuser = True
user.is_staff = True
user.save(using=self._db)
return user
class Account(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(verbose_name="email", max_length=60, unique=True)
username = models.CharField(verbose_name='username', unique=True, max_length=60, null=True)
profile_pic = models.ImageField(blank=False, null=True)
address = models.CharField(verbose_name='address', max_length=200, null=True)
phone_number = models.IntegerField(verbose_name='phone_number', null=True)
car = models.CharField(verbose_name='car' , max_length=60, blank=False, null=True)
details = models.CharField(verbose_name='details', unique=True, max_length=60, blank=False, null=True)
last_login = models.DateTimeField(verbose_name='last_login', auto_now=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email']
objects = MyAccountManager()
def __str__(self):
return self.username
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
#property
def profile_picURL(self):
try:
url = self.profile_pic.url
except:
url = ''
return url
class UserProfile(models.Model):
user = models.OneToOneField(Account, on_delete=models.CASCADE)
avatar = models.ImageField(upload_to = 'static/images')
forms.py
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import UserCreationForm
from accounts.models import Account, UserProfile
class RegistrationForm(UserCreationForm):
email = forms.EmailField(widget=forms.EmailInput(attrs={'placeholder': 'email'}), help_text='Required. Add a valid email address')
username = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'username'}))
#profile_pict = forms.ImageField()
address = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'address'}))
phone_number = forms.IntegerField(widget=forms.TextInput(attrs={'placeholder': 'phone_number'}))
car = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'car'}))
details = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'details'}))
profile_picture = forms.ImageField()
class Meta:
model = Account
fields = ('email', 'username', 'address', 'phone_number', 'car', 'details')
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('user', 'avatar')
def clean_avatar(self):
avatar = self.cleaned_data['avatar']
return avatar
and the template:
{% load static %}
{% include 'others/base.html' %}
{% include 'others/sidebar.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="card"style="margin-top: 58px; margin-left: 300px; margin-right: 20px; height: 45px;">
<h3 style="text-align: center; color: black;">Register New Drivers</h3>
<div class="form" style=" height: 600px; padding-top: 60px; padding-left: 50px; background-color: gainsboro;">
<form method="POST">
{% csrf_token %}
<div class="form-row" >
<div class="col-md-6 mb-0">
{{ form.email|as_crispy_field }}
</div>
<div class="col-md-6 mb-0">
{{ form.username|as_crispy_field }}
</div>
<!--<div class="col-md-6 mb-0">
{{ form.profile_picture|as_crispy_field }}
</div>-->
<div class="col-md-12 mb-0">
{{ form.address|as_crispy_field }}
</div>
<div class="col-md-6 mb-0">
{{ form.phone_number|as_crispy_field }}
</div>
<div class="col-md-6 mb-0">
{{ form.car|as_crispy_field }}
</div>
<div class="col-md-12 mb-0">
{{ form.details|as_crispy_field }}
</div>
<input style="margin-left: 10px;" class="btn btn-primary" type="submit" href ="{% url 'home' %}" value="Sign Up">
</div>
</form>
</div>
</div>
{% endblock %}
I would really appreciate your help...its giving me a headache and cant understand why really the data isnt being saved to my database!!!
adding the urls.py
from django.contrib.auth import views as auth_views
from django.urls import path
from . import views
urlpatterns = [
path('accounts/register', views.register, name='register'),
path('accounts/login/', auth_views.LoginView.as_view(template_name = 'accounts/login.html'), name='login'),
path('logout/', auth_views.LogoutView.as_view(template_name='accounts/logout.html'), name='logout'),
]
It seems that form is not going to register view, kindly check it as the name you have mentioned to redirect is home in href of input tag (maybe the name is register or something else check it), also suggest not to mention anything like action or href as Django by default take current page route, so:
Template file:
<form method="POST" action="{% url 'register' %}">
{% csrf_token %}
<div class="form-row" >
<div class="col-md-6 mb-0">
{{ form.email|as_crispy_field }}
</div>
<div class="col-md-6 mb-0">
{{ form.username|as_crispy_field }}
</div>
<!--<div class="col-md-6 mb-0">
{{ form.profile_picture|as_crispy_field }}
</div>-->
<div class="col-md-12 mb-0">
{{ form.address|as_crispy_field }}
</div>
<div class="col-md-6 mb-0">
{{ form.phone_number|as_crispy_field }}
</div>
<div class="col-md-6 mb-0">
{{ form.car|as_crispy_field }}
</div>
<div class="col-md-12 mb-0">
{{ form.details|as_crispy_field }}
</div>
<input style="margin-left: 10px;" class="btn btn-primary" type="submit" value="Sign Up">
</div>
</form>
views.py:
def register(request):
form = "" # for the error -- local variable 'form' referenced before assignment if occurs.
if request.method == "POST":
form = RegistrationForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'User successfully registered!')
return redirect('home')
else:
print('Form is not valid')
print(form.errors)
else:
form = RegistrationForm()
return render(request, 'accounts/register.html', {'form': form})
RegisterForm doesn't save data because form.is_valid() is False.
for your RegisterForm
as long as you are using file(image) field in your form you should add enctype to your form tag in template, following :
<form method="POST" enctype="multipart/form-data">
also for using ImageField inside your model you should install Pillow library too.
and inside your register view you should instantiate your form like this:
form = RegistrationForm(request.POST, request.FILES)
How to I bind User fields data and user profile data to a model form on my view, I only get user data rendered to a form when i use instance=user but it doesn't render any data of user profile on instance=profile, what i need is to render all user and its profile to a form.
models.py
class User(AbstractUser):
is_supervisor = models.BooleanField(default=False)
is_student = models.BooleanField(default=False)
class Supervisor(models.Model):
user = models.OneToOneField('User', on_delete=models.CASCADE, primary_key=True, related_name='supervisor')
su_mobile_number = models.CharField(max_length=200)
view.py
def supervisor_update(request, user_id):
# user = get_object_or_404(User, pk=user_id)
user = get_object_or_404(User, pk=user_id)
profile = get_object_or_404(Supervisor, pk=user_id)
if request.method == 'POST':
form = SupervisorSignUpForm(request.POST, instance=user)
else:
form = SupervisorSignUpForm(instance=user)
return save_user_form(request, form, 'partials/partial_supervisor_update.html')
form.py
class SupervisorSignUpForm(UserCreationForm):
su_mobile_number = forms.CharField(label="Mobile Number")
class Meta(UserCreationForm.Meta):
model = User
fields = ('username', 'email', 'password1', 'password2', 'first_name', 'last_name')
supervisor_update.html
{% load crispy_forms_tags %}
<form method="post" action="{% url 'supervisor_update' form.instance.pk %}" class="js-supervisor-update-form">
{% csrf_token %}
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Update Supervisor</h4>
</div>
<div class="modal-body">
{% include 'partials/form_messages.html' %}
{{ form.username|as_crispy_field }}
{{ form.email|as_crispy_field }}
{{ form.first_name|as_crispy_field }}
{{ form.last_name|as_crispy_field }}
{{ form.su_mobile_number|as_crispy_field }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Update Supervisor</button>
</div>
</form>
To set the extra field passing in initial along with the user instance should work
initial = {'su_mobile_number': profile.su_mobile_number}
form = SupervisorSignUpForm(instance=user, initial=initial)
Or if you dont want to manually create the dict you could use model_to_dict
from django.forms.models import model_to_dict
initial = model_to_dict(profile, exclude=['user'])
form = SupervisorSignUpForm(instance=user, initial=initial)
Also at the top of your view you are assuming user and supervisor have the same id which could not be the case instead you could do something like this
user = user = get_object_or_404(User, pk=user_id)
profile = user.supervisor
if not profile:
raise Http404
I'm trying to create a custom form where the user can also enter his name for instance but I am facing an issue, when the registration is done the name is not saved and I can't show it on the template.
here is the code
views.py
def register_user(request):
if request.user.is_authenticated():
return HttpResponseRedirect('/user/')
else:
if request.method == 'POST':
form = MyRegistrationForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/user/')
context = {}
context.update(csrf(request))
context['form'] = MyRegistrationForm()
return render(request, 'register.html', context)
forms.py
class MyRegistrationForm(UserCreationForm):
email = forms.EmailField(required=True)
name = forms.CharField(required=True)
class Meta:
model = User
fields = {'name', 'username', 'password1', 'password2', 'email'}
def save(self, commit=True):
user = super(MyRegistrationForm, self).save(commit=False)
user.email = self.cleaned_data['email']
user.name = self.cleaned_data['name']
if commit:
user.save()
return user
register.html
<form action="/user/register/" method="post" id="register" autocomplete="off">
{% csrf_token %}
<div class="fieldWrapper">
{{ form.name.errors }}
{{ form.name.label_tag }}
{{ form.name }}
</div>
[... other form fields ...]
</div>
<input type="submit" value="Register"/>
</form>
So when I submit the form, everything works but when I try to show {{ user.name }} in the template, nothing is shown, why is that? (it works for the email field)
The default User object doesn't have a name field (so you are actually just saving the content of your name field to the object, and not the database). It has a first_name and last_name so you can either use those fields instead or you can customize the User model to have a separate name field
Edit
Also, just so you know, if you use the first_name and last_name fields instead, the User model has a get_full_name() method built-in which might be useful
The User does not have a "name" field. Try:
{{ user.username }}
I'm trying to write a small Django system. After logging into the system, a user can edit and save his/her own profile information. The fields involved are: username, email, first name, last name, website and picture.
The problem: The picture cannot be updated (After selecting an image and clicking "update" button, it shows "No file selected". The profile picture displayed on the page is still the old one). But the other fields are all OK.
Here are my codes:
models.py:
class UserProfile(models.Model):
user = models.OneToOneField(User)
website = models.URLField(blank=True)
picture = models.ImageField(upload_to="profile_images", blank=True)
def __str__(self):
return self.user.username
forms.py:
class UserForm2(forms.ModelForm):
class Meta:
model = User
fields = ('username', 'email', 'first_name', 'last_name')
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('website', 'picture')
views.py:
#login_required
def update_user(request):
try:
user_profile = UserProfile.objects.get(user=request.user)
except UserProfile.DoesNotExist:
return HttpResponse("invalid user_profile!")
if request.method == "POST":
update_user_form = UserForm2(data=request.POST, instance=request.user)
update_profile_form = UserProfileForm(data=request.POST, instance=user_profile)
if update_user_form.is_valid() and update_profile_form.is_valid():
user = update_user_form.save()
profile = update_profile_form.save(commit=False)
profile.user = user
if 'picture' in request.FILES:
profile.picture = request.FILES['picture']
profile.save()
else:
print(update_user_form.errors, update_profile_form.errors)
else:
update_user_form = UserForm2(instance=request.user)
update_profile_form = UserProfileForm(instance=user_profile)
return render(request,
'userprofile/update_user.html',
{'update_user_form': update_user_form, 'update_profile_form': update_profile_form}
)
update_user.html:
<form id="update_user_form" method="POST" action="/userprofile/update_user/">
{% csrf_token %}
{{ update_user_form.as_p }}
{{ update_profile_form.as_p }}
<img src="{{ update_profile_form.instance.picture.url }}" />
<br />
<input type="SUBMIT" name="submit" value="Update"/>
</form>
How can I make it work properly?
To upload the file you should add the enctype attribute to the <form> tag:
<form id="update_user_form" method="POST" action="/userprofile/update_user/"
enctype="multipart/form-data">