Can someone please explain this?? I'm in the process of trying my first post-tutorial project.
I've made a model called Profile with 4 attributes (given_name, surname, bio, image). I've made a form called ProfileForm which inherits from UserCreationForm and i've added the 4 attributes of my model into the form as form attributes.
MY Question is:
Why does it only work like this
class Meta:
model = User
This is my models.py file
class Profile(models.Model):
given_name = models.CharField(max_length=255)
surname = models.CharField(max_length=255)
bio = models.TextField(blank=True, null=True)
image = models.ImageField(upload_to='uploads/', blank=True, null=True)
def __str__(self):
return self.given_name
class Meta:
ordering = ['given_name']
This is my forms.py file
class ProfileForm(UserCreationForm):
firstName = forms.CharField(max_length=255)
lastName = forms.CharField(max_length=255)
bio = forms.CharField(widget=forms.Textarea)
image = forms.ImageField()
class Meta:
model = User
fields = ['firstName', 'lastName', 'username', 'password1', 'password2', 'bio', 'image']
This is my views.py file
def sign_up_view(request):
if request.method == "POST":
form = ProfileForm(request.POST, request.FILES)
if form.is_valid():
user = form.save()
login(request, user)
profile = Profile.objects.create(
given_name=form.cleaned_data['firstName'],
surname = form.cleaned_data['lastName'],
bio = form.cleaned_data['bio'],
image = form.cleaned_data['image'])
return redirect('home')
else:
form = ProfileForm()
return render(request, 'core/sign_up.html', {"form": form})
This is my admin page for a profile.
This is my admin page for a User
Note : I'm able to achieve my desired outcome, but I'm having trouble in understanding how its working.
**Also if i wanted to link the Profile model with the User such that, if the User is deleted in admin then the respective profile would also get deleted??
It only works with model = User, because your fields, like username, etc. are fields of the User model, not of the Profile model.
What you can do is process the view with two forms. We thus make a form for the Profile model, and use the UserCreationForm for the User.
Furthermore the Profile needs to link to the user model, such that it is clear what Profile belongs to what user. We thus add a ForeignKey with:
from django.conf import settings
class Profile(models.Model):
# ⋮
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
editable=False
)
# ⋮
then we can define a Profile form with:
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = '__all__'
then we can work with two forms, the view looks like:
from django.contrib.auth.forms import UserCreationForm
def sign_up_view(request):
if request.method == 'POST':
user_form = UserCreationForm(request.POST, request.FILES)
profile_form = ProfileForm(request.POST, request.FILES, prefix='profile')
if user_form.is_valid() and profile_form.is_valid():
user = form.save()
profile_form.instance.user = user
profile_form.save()
login(request, user)
return redirect('home')
else:
user_form = UserCreationForm()
profile_form = ProfileForm(prefix='profile')
context = {'user_form': user_form, 'profile_form': profile_form}
return render(request, 'core/sign_up.html', context)
and in the template render it with:
<form action="{% url 'name-of-the-signup-view' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ user_form }}
{{ profile_form }}
</form>
we thus use two Django forms in the same HTML form, and prefix the ProfileForm with profile for the input fields.
Related
I am creating an e-commerce website where people can choose to login or not but still the can order and checkout (even if you are an AnonymousUser or Guest user). Now, I am making a login and register form in my website. The login form works and looks good but the register form wasn't working and throwing an error that said "RelatedObjectDoesNotExist at / User has no customer."
I think the reason is that when I register, it only makes a User in database but didn't register anything in the Customer table (which consists Name and Email). How can I register a Customer and User at the same time when I hit the "Submit" button? And how can I make that specific User have "Staff status" only and cannot make changes in the Admin site?
Also, I want to add new fields in the Register form for Name and Email that will go directly to the Customer table. I tried to do this one but it doesn't work and throwed and error that says "django.core.exceptions.FieldError: Unknown field(s) (name) specified for User".
Here's what I did:
from django.forms import ModelForm
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from .models import *
class CustomUserCreationForm(UserCreationForm):
name = models.CharField(max_length=200, null=True)
email = models.CharField(max_length=200)
class Meta:
model = User
fields = ['username', 'name', 'email', 'password1', 'password2']
SUMMARY:
I want to add extra fields in the Register form called Name and Email. Then after clicking the Register form, I want create User and Customer at the same time. But the User should only have "Staff status" and cannot make changes in the Admin site. And the Name and Email field should go to Customer Table with the User I've created.
Here's the screenshot of my Register form:
Here's my forms.py file:
from django.forms import ModelForm
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class CustomUserCreationForm(UserCreationForm):
class Meta:
model = User
fields = ['username', 'password1', 'password2']
def __init__(self, *args, **kwargs):
super(CustomUserCreationForm, self).__init__(*args, **kwargs)
self.fields['username'].widget.attrs.update({'class':'form-control','placeholder':'Enter Username'})
self.fields['password1'].widget.attrs.update({'class':'form-control','placeholder':'Enter Password'})
self.fields['password2'].widget.attrs.update({'class':'form-control','placeholder':'Confirm Password'})
Here's my views.py file:
def loginUser(request):
page = 'login'
if request.method == "POST":
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
print('USER:', user)
if user is not None:
login(request, user)
return redirect('/')
return render(request, 'store/login_register.html', {'page': page})
def logoutUser(request):
logout(request)
return redirect('/')
def registerUser(request):
page = 'register'
form = CustomUserCreationForm()
if request.method == "POST":
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.save()
user = authenticate(request, username=user.username, password=request.POST['password1'])
if user is not None:
login(request, user)
return redirect('/')
context = {'form': form, 'page': page}
return render(request, 'store/login_register.html', context)
Here's my models.py file:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Customer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length=200, null=True)
email = models.CharField(max_length=200)
def __str__(self):
return self.name
Here's my register.html file:
<form class="form" method="POST">
{% csrf_token %}
<h2> REGISTER </h2>
<h4> Create your account now! </h4>
<br />
{% for field in form %}
<div class="mb-3">
<label for="exampleInputPassword1" class="form-label">{{field.label}}:</label>
{{field}}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">Submit</button>
<br />
<p> Already have an account? Login here </p>
</form>
i have registration and login forms that work well, but I am trying to edit the user profile but i don't seem to make it work, below are my codes, can you please point me the mistake i am making?
/views.py
#login_required()
def profile(request):
if request.method == 'POST':
# current_user = UserProfile.objects.get(username=request.user)
form = UserDetailsUpdate(request.POST, instance=request.user)
if form.is_valid():
form.save(commit=True)
return redirect('profile')
form = UserDetailsUpdate(instance=request.user)
return render(request, 'profile.html', {'form': form})
/models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
sex = models.CharField(max_length=20, blank=True)
website = models.URLField(blank=True)
image = models.ImageField(blank=True)
def __str__(self):
return self.user.username
/forms.py
class UserDetailsUpdate(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('image', 'website', 'sex')
/template/profile.html
{% if form %}
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<div class="container">
{{ form.as_p }}
<input type="submit" value="Submit">
</div>
</form>
{% endif %}
looking at your model, i think you have some few things you missed,
there is no way to associate the UserProfile model to the onetoone relationship you have with the User model.
secondly the instance been passed to UserDetailsUpdate form should have reference to the UserProfile model.
Lastly in order to get the update fields populated with current data use also have to use the answer to my second point.
below is your solution.
Create your models here.
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
sex = models.CharField(max_length=20, blank=True)
website = models.URLField(blank=True)
image = models.ImageField(blank=True)
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
the above code will create a corresponding userprofile model anytime a new user is created.
/views.py
#login_required()
def profile(request):
if request.method == 'POST':
# current_user = UserProfile.objects.get(username=request.user)
form = UserDetailsUpdate(request.POST, instance=request.user.userprofile)
if form.is_valid():
form.save(commit=True)
return redirect('profile')
form = UserDetailsUpdate(instance=request.user.userprofile)
return render(request, 'profile.html', {'form': form})
I created a Form using one of my models i.e (Post), for my blog website. The form is meant for writers to post articles. In that form there is an Image attribute where the writer can upload an image. However, when i try to upload an image and post it, i get a feedback saying "field required", i think the form is not recognizing the image am trying to upload onto the the database. please help:
this is the form view from views.py:
def formview(request):
form = PostForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return render(request, 'form.html', {'form':form})
this is from forms.py:
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
image = forms.FileField
class Meta:
model = Post
fields = ['category', 'title', 'body', 'image', 'author']
this from my models.py:
class Post(models.Model):
category = models.ForeignKey(Category)
title = models.CharField(max_length=100)
pub_date = models.DateTimeField(auto_now_add=True)
body = models.TextField()
image = models.FileField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
likes = models.IntegerField(default=1)
def __str__(self):
return self.title
this is my forms.html template:
<form method="POST" action="">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Post</button>
this is my urls.py:
from django.conf.urls import url
from . import views
app_name = 'posts'
urlpatterns = [
url(r'^$', views.homeview, name='homeview'),
url(r'^(?P<pk>[0-9]+)$', views.postview, name='postview'),
url(r'^category/(?P<pk>[a-zA-Z0-9]+)/$', views.categoryview,
name='categoryview'),
url(r'^author/(?P<pk>[a-zA-Z0-9]+)/$', views.authorview, name='authorview'),
url(r'^add_post/$', views.formview, name='formview'),
]
these are the pics might help explain what am trying to say:
Filling the form and selecting the picture
Error message after trying to post
Thank you
def formview(request):
if request.method == 'POST':
form = PostForm(request.POST,request.FILES)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
else:
form = PostForm()
return render(request, 'form.html', {'form':form})
this form = PostForm(request.POST,request.FILES),you need add FILES to PostForm
I am having a problem with displaying a profile picture for every user after the user is done with the registration. I can see the pictures are being saved after the upload to the /media/profile_pictures folder, but I can't find a way to display that picture on the homepage.
Please look at the code samples. I was following the Tango with Django tutorial for uploading a picture, but none of the questions that I found here and are related to this problem did not really help me.
forms.py:
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 = ('website', 'picture')
views.py:
def register(request):
context = RequestContext(request)
registered = False
if request.method == 'POST':
user_form = UserForm(data=request.POST)
profile_form = UserProfileForm(data=request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.save()
profile = profile_form.save(commit=False)
profile.user = user
if 'picture' in request.FILES:
profile.picture = request.FILES['picture']
profile.save()
registered = True
else:
print (user_form.errors, profile_form.errors)
else:
user_form = UserForm()
profile_form = UserProfileForm()
return render(request,'webapp/register.html', {'user_form': user_form, 'profile_form': profile_form, 'registered': registered})
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 __unicode__(self):
return self.user.username
settings.py
MEDIA_URL = '/media/profile_images/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
home.html:
<img src="{{ user.UserProfile.picture.url }}" width="240">
And in the urls.py I have added
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
If you lowercase UserProfile I think it will work:
<img src="{{ user.userprofile.picture.url }}" width="240">
The documentation for OneToOneField says:
If you do not specify the related_name argument for the OneToOneField, Django will use the lower-case name of the current model as default value.
Okay I'm confused.
I'm trying to build a login page, but whenever I try to login, django gives the error that the username already exists. I haven't used save() anywhere.
I'm using authenticate(), I referred the Django docs for that:
https://docs.djangoproject.com/en/1.10/topics/auth/default/#how-to-log-a-user-in
Here is my code, please tell me where I'm going wrong:
forms.py
class LoginForm(forms.ModelForm):
username = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Username'}))
password = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': 'Password'}))
class Meta:
model = User
fields = ['username', 'password']
views.py
class LoginFormView(View):
form_class = LoginForm
template_name = 'login.html'
# display a blank form
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
# authenticate user
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect('slrtcebook:home')
return render(request, self.template_name, {'form': form})
login.html
<div class="form-container">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
{{ field }}
{{ field.errors }}
{% endfor %}
<input id="submit" type="submit" value="Log in" />
</form>
</div>
<p>Don't have an account? Register here</p>
Don't use a ModelForm for this; it will assume you're trying to create a user, and validate that you can do so with the data you've entered. Just use a standard form - inherit from forms.Form and remove the Meta class.
For those of you who want the code here is what I did to fix it:
inside of views.py:
class UserLoginView(View):
form_class = LoginForm
template_name = 'music/login_form.html'
#display a blank form
def get(self, request):
form = self.form_class(None)
return render(request, self.template_name, {'form': form})
#proces form data
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
# user = form.save(commit=False)
#cleaned (normalized) data
username = form.cleaned_data['username']
password = form.cleaned_data['password']
# user.set_password(password) #this is the only way to change a password because of hashing
#returns the User obejects if credintials are correct
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect('music:index')
return render(request, self.template_name,{'form': form})
inside of froms.py:
class LoginForm(forms.Form):
username = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Username'}))
password = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': 'Password'}))
fields = ['username', 'password']
don't forget to also import LoginForm at the top of views.py, where you import UserForm:
from .forms import UserForm, LoginForm