Okay so it appears I'm in way over my head on this small task. I'd like to ask how exactly does one submit to a form, without relying on the URL values?
In my example, the user has to log in before they can see their gallery pictures. Determining this is via "context", which has the active user (as logged in) assigned to it. Props to #chem1st & #Daniel-Roseman for the assistance earlier in helping me figure that out yesterday. Now it can display their own user gallery in the homepage after they log in.
I prefer not uploading with "blahblah.com/bobby/upload", because it doesn't seem very secure. I'd like to let logged in users upload via "blahblah.com/upload/". Which means the form in the view.py would have to get the context of the user who's logged in, somehow, and save the data to the database under that account.
I've been toying around, and searching for answers, but can't find anything. Can someone help point me in the right direction?
Here's my models.py
class UserProfile(models.Model):
user = models.OneToOneField(User)
activation_key = models.CharField(max_length=40, blank=True)
key_expires = models.DateTimeField(default=datetime.date.today())
def __str__(self):
return self.user.username
class Meta:
verbose_name_plural='User profiles'
class ImageDoc(models.Model):
user = models.ForeignKey(UserProfile)
imgfile = models.ImageField(upload_to='images/')
forms.py:
class RegistrationForm(UserCreationForm):
email = forms.EmailField(required=True, widget=forms.TextInput(attrs={'placeholder': 'E-mail address'}))
first_name = forms.CharField(required=True)
last_name = forms.CharField(required=True)
class Meta:
model = User
fields = ('first_name', 'last_name', 'email', 'username', 'password1', 'password2')
class ImgDocForm(forms.Form):
user_file = forms.ImageField()
def clean_user_file(self, *args, **kwargs):
cleaned_data = super(ImgDocForm,self).clean()
user_file = cleaned_data.get("user_file")
if user_file:
if user_file.size > 5 * 1024 * 1024:
raise forms.ValidationError("Filesize is too big.")
if not os.path.splitext(user_file.name)[1].strip().lower() in ['.jpg','.png','.gif','.jpeg']:
raise forms.ValidationError("File does not look like as picture.")
return user_file
class UserForm(forms.Form):
class Meta:
model = User
fields = ['first_name', 'last_name', 'password', 'email', 'username']
My views.py file (EDIT: Changed the Index to display the user details, the gallery, and a quick upload function):
def sign_in(request):
context = RequestContext(request)
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user:
if user.is_active:
login(request, user)
return HttpResponseRedirect('/', context)
else:
return HttpResponse("Verify your account!")
else:
return HttpResponse("Invalid login details supplied.")
def populateContext(request, context):
context['authenticated'] = request.user.is_authenticated()
if context['authenticated'] == True:
context['username'] = request.user.username
def index(request):
user_details = UserProfile.objects.get(user=request.user)
gallery = ImageDoc.objects.filter(user_id=request.user.id)
if request.method == 'POST':
form = ImgDocForm(request.POST, request.FILES)
if form.is_valid():
origin_form = form.cleaned_data["user_file"]
origin_name = origin_form.name
original_name = ImageDoc(user_id=request.user.id, imgfile=origin_name)
original_name.save()
return HttpResponse('Saved!')
else:
form = ImgDocForm()
documents = ImageDoc.objects.all()
return render(request, 'test.html', {'documents': documents, 'form': form, 'user_details': user_details, 'gallery': gallery})
def upload(request):
data = {}
thumb_size = (100,100)
micro_thumb_size = (50,50)
if request.method == 'POST':
userform = ImgDocForm(request.POST, request.FILES)
if userform.is_valid():
origin_form = userform.cleaned_data["user_file"]
origin_name = origin_form.name
original_file = os.path.join(settings.MEDIA_ROOT, origin_name)
.
.
.
original_name = ImageDoc(imgfile=origin_name)
original_name.save()
.
.
.
userform = ImgDocForm()
else:
return HttpResponse('Nooo!')
else:
userform = ImgDocForm()
data.update(image_gallery = ImageDoc.objects.only('imgfile'))
data.update(userform=userform)
data.update(csrf(request))
return render(request, 'upload.html', data)
EDIT: I'm sure folks can clean up the index file significantly. Also, not very elegant at the bottom there, but it works.
And the upload.html document:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<div>
<form method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{{ userform.as_p }}
<input type="submit">
</form>
<br><br>
<h2>{{ origin_name }} (original)</h2>
{% if origin_name %}
<img src="{{ MEDIA_URL }}{{ origin_name }}">
{% endif %}
<br><br>
{% if image_gallery %}
{% for image in image_gallery %}
<img src="/{{ image.thumbfile }}">
{% endfor %}
{% endif %}
</div>
</body>
</html>
Thank you!
You can get currently logged in user inside the view as request.user.
Related
Can you please help me
Forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class Registrationform(UserCreationForm):
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
mobile = forms.CharField(max_length=12, min_length=10)
Business_name = forms.CharField(max_length=64)
email = forms.EmailField(required=True)
password2 = None
class Meta:
model = User
fields = ['username', 'first_name', 'last_name', 'mobile', 'email', 'password1', 'Business_name']
def save(self, commit=True):
user = super(Registrationform, self).save(commit=False)
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.mobile = self.cleaned_data['mobile']
user.email = self.cleaned_data['email']
user.Business_name = self.cleaned_data['Business_name']
if commit:
user.save()
return user
views.py
#login_required
def home(request):
return render(request, 'users/home.html', {'user': request.user})
home.html
{% block content %}
<p>
{{ user.Business_name }}
{{ user.first_name}}
{{ user.last_name}}
{{ user.email }}
{{user.username}}
{{ user.mobile }}
</p>
{% end block %}
I don't understand why I am not able to fetch data even though doing the right thing.
Please help me as I am newbie in Django.
Are you trying to access the form or models? if you want to submit form, you need to change your view to
def home(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
pass # does nothing, just trigger the validation
else:
form = ContactForm()
return render(request, 'home.html', {'form': form})
and add form tag to your home.html
<form method="post" novalidate>
{% csrf_token %}
<table border="1">
{{ form }}
</table>
<button type="submit">Submit</button>
</form>
I hope this helps!!
When I try to create a new user, I also want to create their profile at the same time. But there is no data coming from the Profile form. User is created but in Profile creation form I am getting an error.
Here is my models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
StudentID = models.IntegerField(primary_key=True, verbose_name='SID')
image = models.ImageField(default='default.jpeg', upload_to='profile_pics', blank=True)
def __str__(self):
return self.Branch
def save(self, *args, **kwargs):
super(Profile, self).save(*args, **kwargs)
img = Image.open(self.image.path)
if img.height > 300 or img.width > 300:
output_size = (300, 300)
img.thumbnail(output_size)
img.save(self.image.path)
forms.py
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
first_name = forms.CharField()
last_name = forms.CharField()
class Meta:
model = User
fields = ['username', 'email', 'first_name', 'last_name', 'password1', 'password2']
class ProfileCreationForm(forms.ModelForm):
class Meta:
model = Profile
fields = ['StudentID', 'Branch', 'YearOfStudy', 'ContactNumber']
views.py
when I try to print StudentID, I get None value. I think there is data loss.
def register(request):
print("hello")
if request.method == 'POST':
form = UserRegisterForm(request.POST)
form1 = ProfileCreationForm(request.POST)
if form.is_valid() and form1.is_valid():
user = form.cleaned_data.get('username')
StudentID = form.cleaned_data.get('StudentID')
print(StudentID)
profile = form1.save(commit=False)
profile.user = user
form.save()
profile.save()
messages.success(request, f'Your account has been created! You are now able to log in')
print("reached here")
return redirect('login')
else:
form = UserRegisterForm()
form1 = ProfileCreationForm()
context = {
'form': form,
'form1': form1
}
return render(request, 'user/register.html', context)
register.html
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">JOIN TODAY</legend>
{{ form|crispy }}
{{ form1|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Sign Up</button>
</div>
</form>
<div class="border-top pt-3">
<small class="text-muted">Already have an account?<a class="ml-2" href="{% url 'login' %}">Sign In</a></small>
</div>
</div>
{% endblock content %}
StudentID is on form1 not form
StudentID = form1.cleaned_data.get('StudentID')
print(StudentID)
You should also save the User first since it's a required relation for the Profile model
user = form.save()
profile = form1.save(commit=False)
profile.user = user
profile.save()
Apart from what #Iain has pointed out, I think your code in the views has some problem after you run is_valid. Try to fix it like this:
if form.is_valid() and form1.is_valid():
profile = form1.save(commit=False)
user = form.save()
profile.user = user
profile.save()
messages.success(request, 'Your account has been created! You are now able to log in')
return redirect('login')
Let me explain why you might get error, that is profile.user is a User instance, not a string. So putting username will not work. But you can get the user object when you save the form. Like user=form.save(), so use that in profile.user.
I'm using the following line to fill in data into the form.
form = EditProfileForm(request.POST, instance=request.user)
However, no data fills into the form. I just get the empty form. Not sure what's going wrong. I have a profile html where the data from each user shows up, but the line above is not working on the edit page. The model is the default user model. Django version 2.2.3.
#views.py
def editprofile(request):
if request.method == 'POST':
form = EditProfileForm(request.POST, instance=request.user)
if form.is_valid():
agree = form.save(commit=False)
agree.save()
args = {'form': form}
else:
form = EditProfileForm(request.POST)
args = {'form': form}
return render(request, 'profile_edit.html', {'form':form})
Here is my forms.py:
class EditProfileForm(UserChangeForm):
username = forms.CharField(label='Username', widget=forms.TextInput(attrs={'class': "form-control"}))
first_name = forms.CharField(label='First Name', widget=forms.TextInput(attrs={'class': "form-control"}))
last_name = forms.CharField(label='Last Name', widget=forms.TextInput(attrs={'class': "form-control"}))
email = forms.CharField(label= 'Email', widget=forms.EmailInput(attrs={'class': "form-control"}))
class Meta:
model = User
fields = ['username', 'first_name', 'last_name', 'email', 'password']
def save(self, commit=True):
user = super(EditProfileForm, self).save(commit=False)
user.username = self.cleaned_data['username']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
template
{% block content %}
<h3> Please edit your profile here </h3>
<div class="container">
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button href="{% url 'profilepage' %}" type="submit" >Submit</button>
</form>
<br>
</div>
{% endblock %}
Added urls.py
path('profile/', views.profile, name = 'profilepage'),
path('profile/edit/', views.editprofile, name = 'editprofile')
Try adding action to your form tag in template.
Like this:
<form action= "{% url 'editprofile' %}" method="post">
'editprofile' is the url_name of your editprofile view. Also the class Meta and method def save() should be inside your class EditProfileForm() block.
I'm trying to create an edit form for existing users, I have the User model and I associated to it a profile.
The problem is that the fields of profile are empty in the rendered html, however when I created a new user I filled these fields, and when I enter to administration I find the fields are filled.
models.py
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
DEPARTMENT_CHOICES = (('MI', 'Math et info'),
('ST', 'Science et Tech'),
('SM', 'Science de la matiere'))
user = models.OneToOneField(User, on_delete=models.CASCADE)
teacher = models.BooleanField(default=False)
description = models.TextField(blank=True)
department = models.CharField(max_length=35, choices=DEPARTMENT_CHOICES, blank=True)
picture = models.ImageField(upload_to='profile-images', blank=True)
def __str__(self):
return self.user.username
views.py
def profile_view(request):
if request.method == 'POST':
user_form = EditUserForm(request.POST, instance=request.user)
ins = Profile.objects.get(pk=5)
profile_form = EditProfileForm(request.POST, request.FILES, instance=ins)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
user.save()
profile = profile_form.save(commit=False)
profile.user = user
if 'picture' in request.FILES:
profile.picture = request.FILES['picture']
profile.save()
return redirect(home)
else:
user_form = EditUserForm(instance=request.user)
profile_form = EditProfileForm(request.FILES, instance=request.user)
return render(request, 'account/profile.html', {'user_form': user_form,
'profile_form': profile_form})
forms.py
class EditProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('description', 'department', 'picture', )
class EditUserForm(forms.ModelForm):
class Meta:
model = User
fields = ('username', 'email', )
profile.html
{% extends 'manhal/base.html' %}
{% load staticfiles %}
{% load crispy_forms_tags %}
{% block content %}
<div class="col-md-6">
<form method="post" enctype="multipart/form-data" action="{% url 'profile' %}" class="form-horizontal">{% csrf_token %}
<fieldset>
<legend>User Profile</legend>
{{ user_form|crispy }}
{{ profile_form|crispy}}
<input type="submit" value="Save" class="btn btn-primary">
</fieldset>
</form>
</div>
{% endblock %}
First, your if/else block is checking if the request is a POST. Since the else block is not a POST, you do not want to pass any POST data into your form. This will make the form think it's bound with no data.
Also, it looks like you are passing the request.user to your ProfileForm as the instance, but the model on the ProfileForm meta class is expecting a Profile object.
Can you fix those two things and see if it works or not? If it doesn't work, please post some more code (like your templates).
I'm a bit stumped. So I have two models, as shown in models.py
class UserProfile(models.Model):
user = models.OneToOneField(User)
activation_key = models.CharField(max_length=40, blank=True)
key_expires = models.DateTimeField(default=datetime.date.today())
def __str__(self):
return self.user.username
class Meta:
verbose_name_plural='User profiles'
class ImageDoc(models.Model):
user = models.ForeignKey(UserProfile)
imgfile = models.ImageField(upload_to='images/')
It's a simple profile function, and what I'm trying to do is display images related only to the user after they log in.
Here's my views.py file:
def sign_in(request):
context = RequestContext(request)
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user:
if user.is_active:
login(request, user)
return HttpResponseRedirect('/', context)
else:
return HttpResponse("Verify your account!")
else:
return HttpResponse("Invalid login details supplied.")
def populateContext(request, context):
context['authenticated'] = request.user.is_authenticated()
if context['authenticated'] == True:
context['username'] = request.user.username
def index(request):
context = {}
populateContext(request, context)
context.update(image_gallery = ImageDoc.objects.only('imgfile'))
return render(request, 'index.html', context)
In the index.html page, I can display the user who has logged in, thanks to populateContext above. This includes these:
{{ request.user.first_name }} {{ request.user.last_name }} {{ request.user.username }} {{ request.user.email }} {{ request.user.id }}
However, I don't know how to display "imgfile" from the related model. It works if I do this:
{% for x in image_gallery %}
<img src="{{ x.imgfile }}">
{% endfor %}
But only because I updated the context above to include it in. Ideally I want the image to display just on a particular user's page. Exactly like a member gallery. Thank you in advance for any help.
You can write a simple method for UserProfile model, that will return all images related to current user:
class UserProfile(models.Model):
# some stuff here
def get_images(self):
return ImageDoc.objects.filter(user=self)
Now you can access images in a template:
{% for image in user.userprofile.get_images %}
<img src="{{ image.imgfile }}">
{% endfor %}