profile shape not partially saved - django

After the first registration, it transfers to a new form - you can enter a profile email, photo, bio, links to twitter, github and other social networks, 2 models participate: ProfileUser and User. When a person wrote what he wanted and pressed the button, after the transition he clicked on the user and then he was thrown to the profile page, but there, apart from the mail, nothing from the previously entered is shown, when trying to change the profile, nothing is shown either, there is nothing in the form, I went in the admin panel in the model, only the user is also set automatically when switching to creating a profile after registration, other data is simply not entered, please tell me how to fix it
The user appears to me because this is in the registration
profile = ProfileUser.objects.create(user=new_user)
I tried to redo it according to this article did not work
models.py
class ProfileUser(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True)
img = models.ImageField(null=True, blank=True, upload_to='static/images/', validators=[img__size])
birthday = models.DateField(blank=True, null=True)
about = models.TextField(max_length=1000, null=True)
#? social media
twitter = models.URLField(null=True, blank=True)
facebook = models.URLField(null=True, blank=True)
instagram = models.URLField(null=True, blank=True)
telegram = models.URLField(null=True, blank=True)
vk = models.URLField(null=True, blank=True)
reddit = models.URLField(null=True, blank=True)
github = models.URLField(null=True, blank=True)
def __str__(self):
return 'Profile for user {}'.format(self.user.username)
forms.py
class UserEditForm(ModelForm):
class Meta:
model = User
fields = ['email']
class ProfileEditForm(ModelForm):
class Meta:
model = ProfileUser
fields = ['birthday', 'img', 'about', 'twitter', 'facebook','instagram', 'telegram','vk','reddit', 'github']
views.py
Create Profile:
def createProfile(request):
UserForm = UserEditForm()
ProfileForm = ProfileEditForm()
if request.method == 'POST':
print(request.POST)
UserForm = UserEditForm(request.POST)
ProfileForm = ProfileEditForm(request.POST)
if ProfileForm.is_valid():
UserForm.save()
ProfileForm.save()
return redirect('base:home')
context = {'UserForm': UserForm,'ProfileForm': ProfileForm}
return render(request, 'base/profileForm.html', context)
Update Profile:
#login_required(login_url='base:login')
def updateProfile(request,pk):
user = User.objects.get(id=pk)
UserForm = UserEditForm(instance=user)
ProfileForm = ProfileEditForm(instance=user)
if request.method == 'POST':
ProfileForm = ProfileEditForm(request.POST,instance=user)
UserForm = UserEditForm(request.POST,instance=user)
if UserForm.is_valid():
UserForm.save()
ProfileForm.save()
return redirect('base:home')
context = {'user': user,'UserForm': UserForm,'ProfileForm': ProfileForm}
return render(request, 'base/profileForm.html', context)
profileForm.html
{% block content %}
<form class="login__form" method='POST' action="." enctype="multipart/form-data">
{% csrf_token %}
{{ProfileForm.media}}
{{UserForm.as_p}}
{{ProfileForm.as_p}}
<input type="submit" class="btn btn-min" value="Сохранить">
</form>
{% endblock content %}

You will have to pass the ProfileUser instance corresponding to the user to the ProfileEditForm in updateProfile.
ProfileForm = ProfileEditForm(instance=user.profileuser)

Related

how to delete previous uploaded file when a new one gets uploaded using id

I have simple cv upload class for users to upload their resume. it works just fine but when they upload a newer one, the previous wont get deleted.
this is my code:
class ResumeDocument(models.Model):
id = models.AutoField(primary_key=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
cvfile = models.FileField(upload_to="documents", null=True, validators= [validate_file_extension])
#property
def filename(self):
return os.path.basename(self.cvfile.name)
how can I reach the previous id? id = self.id - 1. something like that.
this is my views:
#login_required
def pdf_resume(request):
if request.method == 'POST':
form = DocumentForm(request.POST,request.FILES)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('pdf_resume')
if 'delete' in request.GET:
return delete_item(ResumeDocument, request.GET['id'])
else:
form = DocumentForm()
documents = ResumeDocument.objects.filter(user=request.user)
if documents:
form = DocumentForm(instance=documents[0])
context = {
'form':form,
'documents':documents,
}
return render(request, 'reg/pdf_resume.html', context)
and this is also my HTML code:
<form id="document-form" method="POST" enctype="multipart/form-data" action="{% url 'pdf_resume' %}" autocomplete="off" class="ant-form ant-form-horizontal">
{% csrf_token %}
<p>{{ form }}</p>
<div class="ant-row-flex" style="margin-left: -10px; margin-right: -10px;"></div>
<button id="btn_submit" type="submit"
class="ant-btn ant-btn-primary"
ant-click-animating-without-extra-node="false" style="float: left;"><span>upload</span></button>
</form>
One possible solution is to save all uploaded CVs for each user and track the last uploaded CV with field uploaded_on. You may refer to the below high-level example:
class CVFile(models.Model):
file_name = models.CharField(max_length=200)
cv_file = models.FileField(upload_to="documents", null=True, validators=[validate_file_extension])
uploaded_on = models.DateTimeField(default=timezone.now, blank=True)
class ResumeDocument(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
cv_file = models.ForeignKey(CVFile, on_delete=models.CASCADE)
You will need to amend your HMTL and views.py accordingly.
models.py
class ResumeDocument(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
cvfile = models.FileField(upload_to="documents", null=True, validators=
[validate_file_extension])
views.py(i just look is there any resumedocuments for that user if yes so i give him
the form just if he was editing the existing file)
#login_required
def pdf_resume(request):
if request.method == 'POST':
form = DocumentForm(request.POST,request.FILES)
if form.is_valid():
form.instance.user = request.user
form.save()
return redirect('pdf_resume')
if 'delete' in request.GET:
return delete_item(ResumeDocument, request.GET['id'])
else:
form = DocumentForm()
documents = ResumeDocument.objects.filter(user=request.user)
if documents:#new
form = DocumentForm(instance=documents[0])
context = {
'form':form,
'documents':documents,
}
return render(request, 'reg/pdf_resume.html', context)
now inside your pdf_resume.html your can just pass the 'form' because you already check if that user has a document or not.

Edit UserProfile information in Django

Problem description: UserProfile form doesn't save any data.
I am creating a new User and automatically create a UserProfile object for him (so I'm extending UserProfile), so I can go to admin page and fill all the fields . But when I'm trying to do it from client side, my form just doesn't catch the data.
Also the strangest moment is that I can change username and email using UserChangeForm, so I'm trying to do the same for UserProfileObject.
models.py:
class UserProfile(models.Model):
user = models.OneToOneField(User)
image = models.ImageField(upload_to='profile_image', blank=True)
title = models.CharField(max_length=100, default = '')
first_name = models.CharField(max_length=200, default = '')
last_name = models.CharField(max_length=200, default = '')
subject = models.ManyToManyField('Subject', related_name='tutor_type', default = '', help_text="Select a subject")
AREA_STATUS = (
('Jerusalem', 'Jerusalem'),
('Tel Aviv', 'Tel Aviv'),
('Haifa', 'Haifa'),
('Eilat', 'Eilat')
)
area = models.CharField(max_length=200, choices=AREA_STATUS, blank=True, default='', help_text='Tutor area')
# Foreign Key used because tutor can only have one area, but area can have multiple tutors
# Author as a string rather than object because it hasn't been declared yet in file.
description = models.TextField(max_length=4000, help_text="Enter a brief description about yourself")
charge = models.IntegerField(default = '0')
# ManyToManyField used because Subject can contain many tutors. Tutors can cover many subjects.
# Subject declared as an object because it has already been defined.
LANGUAGE_CHOICES = (
('English','English'),
('Hebrew','Hebrew'),
('Russian','Russian'),
('French','French'),
('Arabic','Arabic'),
)
language = models.CharField('Language', choices = LANGUAGE_CHOICES, max_length=50, null=True)
def __str__(self):
return self.user.username
def display_subject(self):
"""
Creates a string for the subject. This is required to display subject in Admin.
"""
return ', '.join([ subject.name for subject in self.subject.all()[:3] ])
display_subject.short_description = 'Subject'
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = UserProfile.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender = User)
forms.py::
class EditProfileForm(UserChangeForm):
class Meta:
model = User
fields = (
'username',
'email',
'password'
)
class EditExtendedProfileForm(UserChangeForm):
class Meta:
model = UserProfile
fields = '__all__'
exclude = ('user',)
views.py:
def edit_profile(request):
if request.method == 'POST':
form = EditProfileForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
return redirect(reverse('accounts:view_profile'))
else:
form = EditProfileForm(instance=request.user)
args = {'form': form}
return render(request, 'accounts/edit_profile.html', args)
def edit_extended_profile(request):
if request.method == "POST":
form = EditExtendedProfileForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
return redirect(reverse('accounts:view_profile'))
else:
return redirect(reverse('accounts:edit_extended_profile'))
else:
form = EditExtendedProfileForm(instance = request.user)
args = {'form':form}
return render(request, 'accounts/edit_extended_profile.html', args)
edit_extended_profile.html:
{% extends "base.html" %}
{% block head %}
<title>Profile</title>
{% endblock %}
{% block body %}
<div class = "container">
<form method="POST">
{% csrf_token %}
{{form.as_p}}
<button type = "submit" class = "btn btn-success">Submit</button>
</form>
</div>
{% endblock %}
and it is the same template as for edit_profile view.
No traceback, no errors. Any help will be appreciated. Thanks in advance.

Django ImageField won't upload in function based view, but it does in the admin

I've been trying to add some user uploaded profile picture to my website. It works fine when I do it from the admin, the image is showed and all the engines seems to be working fine (image going to the correct upload location and so on). The problem is when I try to do the same thing from my view.
I noticed that the print("upload_location") only appears when I do it from the admin. The weird thing is that all the other fields in my Profile model are working fine (like name "foo" is updated to "foobar") and not only in the admin, but in the view as well. The issue is only with the ImageField.
I believe it could have something to do with the way I'm handling the form.is_valid(), but I've been playing around with that and nothing changed (I know it is working to some extend, since HttpResponseRedirect is working.
Any ideas?
views.py
...
#login_required
def profile_update(request, username=None):
obj = get_object_or_404(User, username=username)
user = obj.profile
form = ProfileForm(request.POST or None, instance = user)
context = {
"form": form
}
if form.is_valid():
form.save()
return HttpResponseRedirect('/profiles/{username}'.format(username=user.user))
template = 'profile_update.html'
return render(request, template, context)
forms.py
from django import forms
from .models import Profile
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = [
"profilePic",
"nome",
...
]
def profile(self, request, user):
print('printing forms')
user.uf = self.cleaned_data['uf']
user.cidade = self.cleaned_data['cidade']
user.telefone = self.cleaned_data['telefone']
user.save()
models.py
...
User = settings.AUTH_USER_MODEL # 'auth.User'
def upload_location(instance, filename):
print("upload_location")
return "%s/%s" %(instance.user, filename)
class Profile(models.Model):
user = models.OneToOneField(User)
id = models.AutoField(primary_key=True)
width = models.IntegerField(default=0, null=True, blank=True,)
height = models.IntegerField(default=0, null=True, blank=True,)
profilePic = models.ImageField(
upload_to = upload_location,
blank=True, null=True,
verbose_name = 'Foto de Perfil',
width_field="width",
height_field="height",
)
...
template.html
...
<form action="" method="POST" enctype="multipart/form-data">{% csrf_token %}
{{ form|crispy }}
<input type="submit" value="Enviar" class="btn btn-primary"/>
</form>
...
You need to add FILES into the form.
form = ProfileForm(request.POST or None, request.FILES or None, instance = user)
Docs: https://docs.djangoproject.com/en/1.10/topics/http/file-uploads/

Updating "about me" field

I'm having a great deal of difficulty trying to submit a quick form to update a user's "About Me" section. It's an optional field, users can leave it blank if they wish. I can't figure it out!
models.py:
class UserProfile(models.Model):
user = models.OneToOneField(User)
activation_key = models.CharField(max_length=40, blank=True)
key_expires = models.DateField(default=datetime.date.today())
about_me = models.CharField(max_length=500, blank=True, null=True, default='')
portfolio_site = models.URLField(max_length=200, blank=True, null=True, default='')
def __str__(self):
return self.user.username
forms.py:
class UserForm(forms.Form):
class Meta:
model = User
fields = ['first_name', 'last_name', 'password', 'email', 'username']
class ProfileForm(forms.Form):
class Meta:
model = UserProfile
fields = ['about_me', 'portfolio_site']
views.py:
#login_required(login_url='sign_in')
def update_about(request, user_id):
# Accquire submitted data and place to "data"
data = request.POST
# Isolate submitted data under "id_about_me", and place it to "about_me"
about_me = data.get('id_about_me')
new_about = UserProfile(id=request.user.id, about_me=about_me)
new_about.save()
return HttpResponse('Great Job!')
If I use "user_id=request.user.id", then it says:
IntegrityError at /update_about/1/
UNIQUE constraint failed: register_userprofile.user_id
If I use "id=request.user.id", then it says:
IntegrityError at /update_about/1/
NOT NULL constraint failed: register_userprofile.user_id
I can handle other updates just fine, but this one has me stumped!
I think it's because you're creating a new instance of your UserProfile model and assigning the same user_id to it, leading to the Unique constraint error. You should first retrieve your already existing model and modify it like so:
new_about = UserProfile.objects.get(user_id=user_request_id)
new_about.about_me = about_me
new_about.save()
Tell me if this works. If user_id is your auto-primary-key field, though, this shouldn't be an issue.
You need to create, or fetch a profile if it already exists:
profile,created = UserProfile.objects.get_or_create(user=request.user)
profile.about_me = about_me
profile.save()
But why don't you use the form?
from django.shortcuts import redirect, render
from .forms import ProfileForm
#login_required(login_url='sign_in')
def update_about(request, user_id):
form = ProfileForm(request.POST or None)
if form.is_valid():
profile = form.save(commit=False)
profile.user = request.user
profile.save()
return redirect('/')
return render(request, 'update_profile.html', {'form': form})
Your template just has the normal form rendering logic:
<form method="POST">
{% csrf_token %}
{{ form }}
<input type="submit">
</form>

How to create and process a form with multiple same fields?

I'm really stuck with this. To show my problem I created a new Django project and started from scratch, focusing only on one single form.
What I'm trying to do is to create a form with several fields of the same name. I tried using modelformset_factory to achieve this but it looks to me like it's not what I really need.
Below is my code (also on dpaste) which currently works fine with one single field called name. How can I create and process a form which would have several name fields? Could somebody point me in the right direction?
# models.py
class Category(models.Model):
name = models.CharField(max_length=30, unique=True)
user = models.ForeignKey(User, blank=True, null=True)
class Meta:
verbose_name_plural = "Ingredience Categories"
def __unicode__(self):
return self.name
# forms.py
class CategoryForm(ModelForm):
class Meta:
model = Category
fields = ('name',)
# views.py
def home(request):
if request.method == 'POST':
catform = CategoryForm(request.POST)
catformInstance = catform.save(commit = False)
catformInstance.save()
return HttpResponseRedirect('')
else:
catform = CategoryForm()
context = {'catform': catform}
return render_to_response('home.html', context, context_instance=RequestContext(request))
# home.html template
<h3>Insert new Category</h3>
<form action="/" method="post" id="ingr-cat-form">{% csrf_token %}
{{ catform.as_p }}
<input type="submit" name="ingrCatForm" value="Save" />
</form>
UPDATE: to clarify, I want to allow user to insert several categories within one form. I think I'm getting close, here is my new version of views.py but it still stores just one category (the last one in the list):
def home(request):
if request.method == 'POST':
catform = CategoryForm(request.POST)
names = request.POST.getlist('name')
catformInstance = catform.save(commit = False)
for name in names:
catformInstance.name = name
catformInstance.save()
return HttpResponseRedirect('')
else:
catform = CategoryForm()
context = {'catform': catform}
return render_to_response('home.html', context, context_instance=RequestContext(request))
You cannot have fields with the same name (on the same Model). If you only need to change the html label in the html form, use
class Category(models.Model):
name = models.CharField(max_length=30, unique=True)
name2 = models.CharField(max_length=30, unique=True, verbose_name="name")
user = models.ForeignKey(User, blank=True, null=True)
or
class CategoryForm(ModelForm):
def __init__(self , *args, **kwargs):
super(CategoryForm, self).__init__(*args, **kwargs)
self.fields['name2'].label = "name"
Here is a working solution. Thanks to #YardenST for pointing me in the right direction. I managed to solve my initial problem by following this tutorial.
# models.py
class Category(models.Model):
name = models.CharField(max_length=30, unique=True)
user = models.ForeignKey(User, blank=True, null=True)
class Meta:
verbose_name_plural = "Ingredience Categories"
def __unicode__(self):
return self.name
# forms.py
class CategoryForm(ModelForm):
class Meta:
model = Category
fields = ('name',)
# views.py
def home(request):
if request.method == 'POST':
catforms = [CategoryForm(request.POST, prefix=str(x), instance=Category()) for x in range(0,3)]
if all([cf.is_valid() for cf in catforms]):
for cf in catforms:
catformInstance = cf.save(commit = False)
catformInstance.save()
return HttpResponseRedirect('')
else:
catform = [CategoryForm(prefix=str(x), instance=Category()) for x in range(0,3)]
context = {'catform': catform}
return render_to_response('home.html', context, context_instance=RequestContext(request))
# home.html template
<h3>Insert new Category</h3>
<form action="/" method="post" id="ingr-cat-form">{% csrf_token %}
{% for catform_instance in catform %} {{ catform_instance.as_p }} {% endfor %}
<input type="submit" name="ingrCatForm" value="Save" />
</form>