I am following a Django tutorial on Youtube, I added a bio field in the UserUpdateForm. There is a slot for me to edit the bio on change_profile.html but when I press the update button it updates everything else except for the bio.
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from .models import Profile
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
# What I added
bio = forms.CharField(required=False)
class Meta:
model = User
fields = ['username', 'email', 'bio']
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['image']
The function that saves the forms
#login_required
def change_profile(request):
if request.method == 'POST':
u_form = UserUpdateForm(request.POST, instance=request.user)
p_form = ProfileUpdateForm(request.POST, request.FILES, instance=request.user.profile)
if u_form.is_valid() and p_form.is_valid():
u_form.save()
p_form.save()
messages.success(request, 'Profile Updated')
return redirect('profile')
else:
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)
context = {
'u_form' : u_form,
'p_form' : p_form
}
return render(request, 'users/change_profile.html', context)
The change_profile.html
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block title %}Change Profile{% endblock title %}
{% block content %}
<div class="content-section">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Edit Profile</legend>
{{ u_form|crispy }}
{{ p_form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Update</button>
</div>
</form>
</div>
{% endblock content %}
And the profile.html
{% extends "blog/base.html" %}
{% block title %}Profile{% endblock title %}
{% block content %}
<div class="content-section">
<div class="media">
<img class="rounded-circle account-img" src="{{ user.profile.image.url }}">
<div class="media-body">
<h2 class="account-heading">{{ user.username }}</h2>
<p class="text-secondary">{{ user.email }}</p>
<p class="article-content">{{ user.bio }}</p>
</div>
</div>
<a class="ml-2" href="{% url 'change_profile' %}">Edit Profile</a>
{% endblock content %}
It's because the default User model has no attribute called bio, so there's nowhere to store the value you're getting from the form. You need to add it to the model first. You can create a custom user model, but since you already have a Profile model, you can store bio along with image:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField()
bio = models.CharField(max_length=225, blank=True, null=True)
And in forms.py add the new field to the field list:
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('image', 'bio')
You could have simply override the the User model and add your custom fields, then you don't need to add extra fields in your form. Check this example:
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
bio = models.TextField()
def __str__(self):
return unicode(self.user)
Make sure you add mention your custom User model in settings:
AUTH_USER_MODEL ='your_app.UserProfile'
Related
I'm coming to you because I have a problem with my form. Let me explain, when I enter the information in the inputs and I click on the button, it does absolutely nothing, without any error message.
This is views.py:
from django.shortcuts import render, redirect
from django.http import HttpResponseRedirect
from .models import Movies
from .forms import CreateUserForm
from django.contrib import messages
from django.contrib.auth.models import User
from django.contrib.auth import authenticate, login, logout
from django.conf import settings
from django.contrib.auth.decorators import login_required
# Create your views here.
def home(request):
context = {
'movies': Movies.objects.all()
}
return render(request, 'list/home.html', context)
#login_required(login_url='login-page')
def add(request):
return render(request, 'list/add.html', {'title': 'Add Movies'})
def signup(request):
if request.method == 'POST':
form = CreateUserForm(request.POST)
if form.is_valid():
form.save(commit=True)
return redirect('list-home')
else:
form = CreateUserForm()
return render(request, 'list/sign.html', {'form': form})
This is forms.py:
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class CreateUserForm(UserCreationForm):
username = forms.CharField(max_length=50, required=True, widget=forms.TextInput(attrs={"placeholder": "Your pseudo:"}))
first_name = forms.CharField(max_length=50, required=True, widget=forms.TextInput(attrs={"placeholder": ">Your first name:"}))
last_name = forms.CharField(max_length=50, required=True, widget=forms.TextInput(attrs={"placeholder": "Your last name:"}))
email = forms.EmailField( max_length=50, required=True, widget=forms.TextInput(attrs={"placeholder": "Your email:"}))
password = forms.CharField(max_length=50, required=True, widget=forms.PasswordInput(attrs={"placeholder": "Your password:"}))
password2 = forms.CharField(max_length=50, required=True, widget=forms.PasswordInput(attrs={"placeholder": "Confirm your password:"}))
class Meta:
model = User
fields = ('username', 'first_name', 'last_name', 'email', 'password', 'password2')
And my sign.html:
{% extends "list/base.html" %}
{% block content %}
<main class="site-main" style="background-color: black; color: white;">
<div class="form-box2">
<h1 style="text-align: center; padding: 20px;">SIGN UP</h1>
<form method="POST" class="conta" style="text-align: center;">
{% csrf_token %}
{{form.username}}
{{form.first_name}}
{{form.last_name}}
{{form.email}}
{{form.password}}
{{form.password2}}
<button type="submit">Sign up</button>
</form>
{% if messages%}
{% for message in messages%}
<div class="alert alert-{{message.tags }}">{{ message }}</div>
{% endfor %}
{% endif %}
</div>
</main>
{% endblock content%}
So here it is, I probably forgot something but I can't find it, I hope you can help me. Thank you in advance for your help.
You're creating a new form if the form is invalid, so there won't be any errors in that new form.
def signup(request):
form = CreateUserForm() # Form for GET request
if request.method == 'POST':
form = CreateUserForm(request.POST) # add the data from POST to the form
if form.is_valid():
form.save(commit=True)
return redirect('list-home')
# An invalid form will end up here with the errors in it.
return render(request, 'list/sign.html', {'form': form})
Looking at your template, because you're just rendering each field you also won't see the errors attached to a field.
While you're getting this up & running, try to get Django to do the most work for you. There may also be other errors, so you should include those if present;
{% if form.non_field_errors %}
<ul>
{% for error in form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{# To really make sure you debug this #}
{{ form.errors }}
<form method="POST" class="conta" style="text-align: center;">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Sign up</button>
</form>
I am trying to go to the author profile if i press on his name. This is my HTML which do these:
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<div class="media">
<img class="rounded-circle account-img" src="{{ user.profile.image.url }}">
<div class="media-body">
<h2 class="account-heading">{{ user.username }}</h2>
</div>
</div>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Profile Info</legend>
<p class="text-secondary"><h3>Contact Me Here: </h3>{{ user.email }}</p>
</fieldset>
</form>
</div>
{% endblock content %}
In my views.py i have this:
def author_profile(request):
user = Post.author
u_form = UserUpdateForm(instance=request.user)
p_form = ProfileUpdateForm(instance=request.user.profile)
context = {
'u_form': u_form,
'p_form': p_form
}
return render(request, 'blog/author_profile.html', context)
Where UserUpdateForm and ProfileUpdateForm from the forms.py have this code:
class UserUpdateForm(forms.ModelForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email']
class ProfileUpdateForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['image']
Class for the Post:
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
If i press on the name it is getting me to the user profile, I tried to work with Post.author but didn't worked.
It's my first time with django.
I extend the django User model with a profile model. I want add update user's profile function. Because I make the num field a unique field, in my update view function, the update form's is_valid was always False. I also cannot update the photo png? Here is my code;
Models:
class Profile(models.model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
num =models.CharField('identity',max_length=254,unique=True)
photo = models.ImageField('image',upload_to = 'images/licences')
forms:
class ProfileForm(forms.ModelForm):
class Meta:
model= Profile
fields = ['num','photo']
views:
def modify_view(request):
user = request.user
if request.method=="POST":
form = ProfileForm(request.POST,request.FILES)
if form.is_valid()
user_profile = Profile.objects.get(user=user)
user_profile.image = form.clean_data['image']
user_profile.save()
else:
form = ProfileForm()
return render(request,"profile.html",{form:form})
template
{% extends 'account/home/index.html' %}
{% block content %}
<div class="row">
<div class="col-md-8 col-sm-8 col-8">
<form class="signup needs-validation" id="signup_form" method="post" enctype="multipart/form-data" >
{% csrf_token %}
{{form.as_p}}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<div class="form-group">
<button type="submit" class="col-sm-8 offset-sm-4 btn btn-success btn-block">update</button>
</div>
</form>
</div>
</div>
{% endblock %}
Since num field is unique and will not be generated again on updating the profile image, you can ignore request.POST and pass the instance argument to the ProfileForm class.
Example:
def modify_view(request):
user = request.user
if request.method=="POST":
user_profile = Profile.objects.get(user=user)
form = ProfileForm(files=request.FILES, instance=user_profile)
if form.is_valid():
user_profile.image = form.clean_data['image']
user_profile.save()
else:
form = ProfileForm()
return render(request,"profile.html",{form:form}
trying to create a registration form, and I am facing an issue. so, below are my python pages:
form.py
from .models import User
from django import forms
from django.forms import ModelForm
class SignUpForm(ModelForm):
class Meta:
model = User
fields = ('username','password','email')
models.py
from django.db import models
#from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
class Registration(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
urls.py
urlpatterns = [
url(r'^register/$', views.SignUpFormView, name= 'register'),
]
test.html
{% extends 'user_info/base.html' %}
{% block body %}
{% block content %}
<form method="POST">
{% csrf_token %}
{{ form }}
username:<br>
<input type="text" name="username"><br>
password:<br>
<input type="text" name="password"><br>
email:<br>
<input type="text" name="email"><br>
<input type="submit" value="Submit" />
</form>
{% endblock %}
{% endblock %}
views.py
def SignUpFormView(request):
template_name = 'test.html'
try:
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
email = form.cleaned_data.get('email')
return render(request, template_name, {'form':form})
except ValueError:
print("Oops! That was not a valid entry, try again...")
else:
SignUpForm()
return render(request, 'user_info/about.html')
The issue is, my "SignUpFormView" function in views.py is not entering the "if" statement, its directly going to "else". I seem to be lost here.
I have 'about.html'. I do not see any error as well. Which I find very weird. Please help.
Note: I am using Django's default in-built "User" model, and I do not wish to create any custom model.
Modified views.py
def SignUpFormView(request):
user_form = 'SignUpForm'
template_name = 'test.html'
if request.method == 'POST':
form = user_form(request.POST)
if form.is_valid():
form.save()
#username = form.cleaned_data.get('username')
#password = form.cleaned_data.get('password')
#email = form.cleaned_data.get('email')
#user.save()
return render(request, template_name, {'form':form})
else:
SignUpForm()
return render(request, 'user_info/about.html')
Modified forms.py
from .models import User
from django import forms
from django.forms import ModelForm
class SignUpForm(forms.ModelForm):
#password = forms.Charfield(widget=forms.PasswordInput)
class Meta:
model = User
fields = ('username','password','email')
modified test.html
{% extends 'user_info/base.html' %}
{% block body %}
{% block content %}
{% for error in form.errors %}
{{ form.errors | default_errors }}
{% endfor %}
<form method="post">
{% csrf_token %}
{{ form.as_p }}
{% for field in form %}
<p>
username:<br>
<input type="text" name="username"><br>
password:<br>
<input type="text" name="password"><br>
email:<br>
<input type="text" name="email"><br>
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button type="submit" value="Submit">sign up </button>
</form>
{% endblock %}
{% endblock %}
I want to add placeholders to my fields but for some reason, this is not working. When I view page source, the placeholder attributes are not even there.
Here is my forms.py:
class RegistrationForm(UserCreationForm):
email = forms.EmailField(required=True, max_length=254)
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2',)
widgets = {
'username' : forms.TextInput(attrs={'placeholder': 'Username'}),
'email' : forms.TextInput(attrs={'placeholder': 'Email'}),
'password1' : forms.TextInput(attrs={'placeholder': 'Password'}),
'password2' : forms.TextInput(attrs={'placeholder': 'Confirm Password'}),
}
This is the template I am using for HTML:
<!DOCTYPE html>
{% extends 'base.html' %}
{% load staticfiles %}
{% block content %}
<section class="container">
<div class="row centre-v">
<div class="card login-card">
<div class="main card-block">
<h1>Sign up</h1>
<div class="login-or">
<hr class="hr-or">
</div>
<form action="." method="post" class="register-form">
{% csrf_token %}
{% for field in form %}
<p>
{{ field }}
{% for error in field.errors %}
<div class="alert alert-danger" role="alert"><strong>{{ error }}</strong></div>
{% endfor %}
</p>
{% endfor %}
<div class="btn-login">
<input class="btn btn-info" type="submit" value="Register">
</div>
</form>
</div>
</div>
</div>
</section>
{% endblock %}
According to the docs for ModelForm, the Meta class is only used to generate fields from the underlying model. Fields which are declared explicitly in the ModelForm class are not affected by the attributes set in Meta. You declare email in your class, and password1 and password2 are declared in the inherited UserCreationForm class. (username is generated automatically, so the widget attribute you set in the Meta class may have worked for that field.) To set attributes for declared fields you can use the self.fields dict.
class RegistrationForm(UserCreationForm):
email = forms.EmailField(required=True, max_length=254)
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2',)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs):
self.fields['username'].widget.attrs['placeholder'] = 'Username'
self.fields['email'].widget.attrs['placeholder'] = 'Email'
self.fields['password1'].widget.attrs['placeholder'] = 'Password'
self.fields['password2'].widget.attrs['placeholder'] = 'Confirm Password'