I'm trying to upload an image. This is an avatar image for the profile of the user.
Currently, the form return no error, but I have nothing written on my database or in my folder media/avatar/.
What's wrong ?
My view :
def view_avatar(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES, instance=request.user.profile)
if form.is_valid():
form.save()
else:
form = UploadFileForm(instance=request.user.profile)
return render(request, 'avatar.html', locals())
My form :
class UploadFileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('avatar',)
My model :
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
birthdate = models.DateField(null=True, blank=True)
avatar = models.ImageField(upload_to='media/avatar/', blank=True, null=True)
It's because the form which you are using is inherited from forms.Form , you need to use forms.ModelForm for saving the instance directly.
Change this line,
class UploadFileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('avatar', )
def save(self, *args, **kwargs):
profile, created = Profile.objects.get_or_create(user=self.user)
profile.avatar = self.cleaned_data['avatar']
profile.save()
return profile
Also, edit in your views like this,
if form.is_valid():
file = form.save(commit=False)
file.user = request.user
file.save()
For making a profile you can use signals.
This way whenever a new user been added, a profile will be generated for that user automatically
Your models.py:
from django.conf import settings
from django.db.models.signals import post_save
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
birthdate = models.DateField(null=True, blank=True)
avatar = models.ImageField(upload_to='media/avatar/%y/%m/%d', blank=True, null=True)
def post_save_profile(sender, instance, created, *args, **kwargs):
if created:
try:
Profile.objects.create(user=instance)
except:
pass
post_save.connect(post_save_profile, sender=settings.AUTH_USER_MODEL)
and for updating the information like birthday and avatar you can use ModelForm.
forms.py:
class UploadFileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('birthdate', 'avatar')
def __init__(self, *args, **kwargs):
super(UploadFileForm, self).__init__(*args, **kwargs)
self.fields['avatar'].required = False
your views.py:
def view_avatar(request):
user = request.user
if request.method == "POST":
form = UploadFileForm(request.POST, request.FILES, instance=user.profile)
if form.is_valid():
form.save()
for avatar in template you can use this:
<img src="{% if user.profile.avatar %}{{ user.profile.avatar.url }}{% else %}{% static 'no-avatar.jpg' %}{% endif %}"><i></i>
You can write custom Save method for this like this.
View:
def view_avatar(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES, user=request.user)
if form.is_valid():
form.save()
else:
form = UploadFileForm()
return render(request, 'avatar.html', locals())
Form:
class UploadFileForm(forms.Form):
class Meta:
model = Profile
fields = ('avatar', )
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super(UploadFileForm, self).__init__(*args, **kwargs)
self.fields['avatar'].required = False
avatar = forms.FileField()
def save(self, *args, **kwargs):
user_profile, created = Profile.objects.get_or_create(user=self.user)
user_profile.avatar = self.cleaned_data.get('avatar')
user_profile.save()
return user_profile
I forgot the enctype !
The solution was :
<form method="POST" action="" enctype="multipart/form-data">
Related
I Have two models Contest and Contestant, users can start a contest, and other users can register as a contestant under any contest…
models.py
class Contest(models.Model):
contest_title = models.CharField(max_length=30)
contest_post = models.CharField(max_length=100)
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
class Contestant(models.Model):
contest = models.ForeignKey(Contest, on_delete=models.CASCADE, related_name='participating_contest')
contestant_name = models.CharField(max_length=10, blank=True, null=True)
votes = models.IntegerField(default=0)
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
Fans of any contestant can cast an unlimited amount of vote for their favourite contestant, anytime a fan votes i want to increment the Contestant.votes with the amount of votes being casted, i have tried using FBV but it is too complicated for my level of django, i am now using CBV, but i am getting an IntegrityError saying IntegrityError at /contests/contestant/2/ NOT NULL constraint failed: contest_contestant.contest_id
this error doesn’t make sense to me because contest_id has already being assigned to contestant upon creation, and i can even confirm it from the database
view.py
class ContestantCreateView(CreateView):
model = Contestant
fields = ['contestant_name']
def form_valid(self, form):
form.instance.contest_id = self.kwargs.get('pk')
return super().form_valid(form)
the voting logic is in side contestant detailView, which is being triggered by a POST request from a form
views.py
class ContestantDetail(DetailView, FormMixin):
model = Contestant
context_object_name = 'contestants'
template_name = 'contest/contestant_detail.html'
form_class = VoteForm
def get_success_url(self):
return reverse('contest:contestant-detail', kwargs={'pk': self.object.pk})
def get_context_data(self, *args, **kwargs):
context = super(ContestantDetail, self).get_context_data(*args, **kwargs)
context['vote_contestant'] = Contestant.objects.get(pk=self.kwargs.get('pk'))
return context
def post(self, request, *args, **kwargs):
form = self.get_form()
self.object = self.get_object()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form, *args, **kwargs):
contestant = Contestant.objects.get(pk=self.kwargs['pk'])
vote_count = form.cleaned_data['votes']
contestant.votes += vote_count
form.save()
messages.success(self.request, f'You have successfully casted your vote.')
return super().form_valid(form)
forms.py
class VoteForm(forms.ModelForm):
class Meta:
model = Contestant
fields = ['votes']
html form template
<form action="" method="post">
{% csrf_token %}
{% include 'contest/bs4_form.html' with form=form %}
<button type="submit">Vote Now</button>
</form>
below is my urls.py
path('contestant/<int:pk>/new/', views.ContestantCreateView.as_view(), name='new-contestant'),
path('contestant/<int:pk>/edit/', views.ContestantUpdateView.as_view(), name='edit-contestant'),
path('contestant/<int:pk>/', views.ContestantDetail.as_view(), name='contestant-detail'),
By making use of form.save() you are saving the form, since you did not pass an instance to the form, that means that form.save() will try to create a new record. You thus should omit form.save() from the form_valid(…) method:
from django.db.models import F
def form_valid(self, form, *args, **kwargs):
contestant = Contestant.objects.get(pk=self.kwargs['pk'])
vote_count = form.cleaned_data['votes']
contestant.votes = F('votes') + vote_count
contestant.save()
# no form.save()
messages.success(self.request, f'You have successfully casted your vote.')
return super().form_valid(form)
I am trying to give a user the option to change his/her first/last name through a ModelForm. When I press submit, I get hit with the UNIQUE constraint failed: auth_user.username error. Here are my codes:
students/forms.py:
class EditProfileForm(UserChangeForm):
def clean_password(self):
# Overriding the default method because I dont want user to change
# password
pass
class Meta:
model = User
fields = (
'first_name',
'last_name',
)
students/views.py:
User = get_user_model()
def student_profile_view(request, slug):
if request.method == 'GET':
# forms
edit_name_form = EditProfileForm(instance=request.user)
context = {
'edit_name_form': edit_name_form,
}
return render(request, "students/profile.html", context)
class ChangeNameView(SuccessMessageMixin, UpdateView):
template_name = 'students/edit_profile.html'
model = User
form_class = EditProfileForm
success_message = "Your name has been updated"
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
form.instance.student_profile = StudentProfile.objects.get(slug=request.user.student_profile.slug)
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
"""If the form is valid, save the associated model."""
form.instance.username = self.request.user
self.object = form.save(commit=False)
return super().form_valid(form)
def get_success_url(self):
return reverse('students:student_profile_view', kwargs={'slug': self.object.student_profile.slug})
also fyi, User model is foreign key with StudentProfile.
students/models.py:
class StudentProfile(models.Model):
user = models.OneToOneField(User, related_name='student_profile', on_delete=models.CASCADE)
slug = models.SlugField(blank=True, unique=True)
avatar = models.ImageField(upload_to='student_profile/', null=True, blank=True)
description = models.CharField(max_length=120, null=True, blank=True)
objects = models.Manager()
def __str__(self):
return self.user.username
def get_absolute_url(self):
return reverse("students:student_profile_view", kwargs={"slug": self.slug})
I am pretty new to class based view so maybe I'm doing something wrong there?
I assume you do not have the user within the form so you need the form
def get_context_data (self, *args, **kwargs)
ctx = super().get_context_data(*args, **kwargs)
if self.request.method == 'POST':
ctx['form'] = EditProfileForm(instance=self.request.user)
and remove def form_valid()
I basically want to associate the logged in user name with the PhotoModel by using models.ForeignKey. I override the safe_model in admin.py but when i execute the views.py class PhotoCreateNew(View) then it stops at print(form) and the form is not validated (if form.is_valid()) skips the entire part which was supposed to set the request.user as photo.user_name and return the empty template.
My models.py
class Photo(models.Model):
user_name = models.ForeignKey(User, on_delete=models.CASCADE)
PLACES = (('RD','研发-R&D'),('Warehouse','仓库-Warehouse'),('Gate','门卫处-Gate Guard'),('SecondFloor','2F生产部'))
photo = models.FileField()
photo_name = models.CharField(max_length=20)
date = models.DateField(auto_now="True")
quantity = models.CharField(max_length=4)
CONDITIONS = (('N','NG'), ('G', 'GOOD'))
condition =models.CharField(max_length=1,choices=CONDITIONS)
place = models.CharField(max_length=30,choices=PLACES,default='Warehouse')
def __str__(self):
return self.photo_name
def get_absolute_url(self):
return reverse('photo:photo_detail', kwargs={'pk':self.pk})
class PhotoForm(ModelForm):
class Meta:
model = Photo
fields =['user_name','photo','photo_name','quantity','condition','place']
exclude= ('user_name',)
My admin.py:
from django.contrib import admin
from photo.models import Photo
from photo.models import Supplier
class PhotoAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
if not obj.pk:
obj.user_name = request.user
obj.save()
admin.site.register(Supplier,)
admin.site.register(Photo, PhotoAdmin)
My views.py:
class PhotoCreateNew(View):
form_class = PhotoForm
template_name = 'photo/photo_form.html'
def get(self, request):
form =self.form_class(None)
return render(request, self.template_name, {'form':form})
def post(self,request):
form = self.form_class(request.POST)
print(request.user)
print(form)
if form.is_valid(): # uploader has been excluded. No more error.
print("Przeszlo")
photo = form.save(commit=False) # returns unsaved instance
photo.user_name = request.user
print(request.user)
photo.save() # real save to DB.
return redirect('photo:photo_detail')
return render(request,self.template_name,{})
After initializing the form class with request.POST and request.FILES it is working.
I had to replace :
form = self.form_class(request.POST)
with :
form = self.form_class(request.POST, request.FILES)
My form was working fine but suddenly it stops working and I'm stuck here, help me please!
When I prints form.errors in case of form not valid then it prints
user is a required field.
models.py
class TarWithDocker(models.Model):
name = models.CharField(max_length=255)
user = models.ForeignKey(User, related_name='deployments')
slug = AutoSlugField(populate_from='name', unique=True, name='slug')
archive = models.FileField(upload_to='archives', name='archive')
created_at = models.DateTimeField(default=timezone.now, editable=False)
class Meta:
ordering = ['-created_at']
views.py
class AwdDeployment(LoginRequiredMixin, CreateView):
template_name = 'deployments/awdDeployment.html'
def get(self, request, *args, **kwargs):
return render(request, 'deployments/awdDeployment.html', {})
def post(self, request, *args, **kwargs):
if request.method == 'POST':
form = AwdDeploymentForm(request.POST, request.FILES)
if form.is_valid():
deployment = TarWithDocker()
deployment.name = form.cleaned_data['name']
deployment.user = self.request.user
deployment.archive = form.cleaned_data['archive']
deployment.save()
return HttpResponse("Submitted")
else:
print("not saved")
else:
print("something happnes wrong")
form = AwdDeploymentForm()
return HttpResponseRedirect(reverse('users:deployments:awd'))
You have user in request, but may be not in post data
May be it help you:
post_data = request.POST.copy()
post_data.update({'user': request.user.pk})
form = AwdDeploymentForm(post_data, request.FILES)
I need to set the user that is creating the post in the add view:
#login_required
def add(request):
if request.method == 'POST':
form = BusinessForm(request.POST)
form.user_id = request.user.id
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('listing.views.detail'), args=(f.id))
else:
form = BusinessForm()
return render_to_response('business/add.html', {'form':form},
context_instance=RequestContext(request))
I assign the user id form.user_id = request.user.id but when saving, it still gives me an error Column user_id cannot be null
Am I doing something wrong? Thanks
EDIT:
I am excluding the user from the form in the model:
class BusinessForm(ModelForm):
class Meta:
model = Business
exclude = ('user',)
Could that be causing the problem?? How can I work around this?
EDIT 2:
Edited my BusinessForm() class as suggested but did not work:
class BusinessForm(ModelForm):
class Meta:
model = Business
exclude = ('user',)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
return super(BusinessForm, self).__init__(*args, **kwargs)
def save(self, *args, **kwargs):
kwargs['commit']=False
obj = super(BusinessForm, self).save(*args, **kwargs)
if self.request:
obj.user = self.request.user
obj.save()
Business model
class Business(models.Model):
name = models.CharField(max_length=200)
user = models.ForeignKey(User, unique=False)
description = models.TextField()
category = models.ForeignKey(Category)
address = models.CharField(max_length=200)
phone_number = models.CharField(max_length=10)
website = models.URLField()
image = models.ImageField(upload_to='business_pictures',blank=True)
You don't have to use init or save overrides for this.
You're just setting an attribute on your form and the form doesn't do anything with it. It doesn't magically behave like a model instance (your form wouldn't have a user_id attribute).
Since your form is a ModelForm, you can simply call save on it with commit=False to get the unsaved instance, set the user, then call save on the instance.
if request.method == 'POST':
form = BusinessForm(request.POST)
if form.is_valid():
business = form.save(commit=False)
business.user = request.user
business.save()
this seems to be exactly what your looking for.