Django, user can update email and username but not Image - html

As in title I have a problem with updating form because everything works as I want but not an image updating feature.It sends success message but it does not change the image for the profile.
views.py
def profileView(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, 'Your account has been updated!')
return redirect('profile-page')
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, 'shop/profile.html', context)
HTML:
<div>
{{ user.username }}
<img src="{{ user.profile.user_image.url }}">
Delete
<form method="POST"> {% csrf_token %}
{{ p_form.as_p}}
{{ u_form.username }}
{{ u_form.email }}
<button type="submit">Update</button>
</form>
</div>
signals.py
#receiver(post_save, sender=User)
def profile_creation(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()
{{ u_form.email }}
<button type="submit">Update</button>
</form>
</div>

If you send files in a form, you specify the enctype="multipart/form-data" attribute to encode images in the POST request:
<form enctype="multipart/form-data" method="POST">
{% csrf_token %}
{{ p_form.as_p}}
{{ u_form.username }}
{{ u_form.email }}
<button type="submit">Update</button>
</form>

Related

Django: div class alert alert-danger does not work properly

My forms.py:
class SignUpForm(forms.ModelForm):
name = forms.CharField(label="name", required=True, widget=forms.TextInput())
email = forms.CharField(label="email", required=True, widget=forms.TextInput())
password = forms.CharField(label="password", widget=forms.PasswordInput(), required=True)
confirm_password = forms.CharField(label="password", widget=forms.PasswordInput(), required=True)
def clean(self):
cleaned_data = super(SignUpForm, self).clean()
password = cleaned_data.get("password")
confirm_password = cleaned_data.get("confirm_password")
if password != confirm_password:
self.add_error('confirm_password', "Password and confirm password do not match")
return cleaned_data
class Meta:
model = get_user_model()
fields = ('name', 'email', 'password')
My html file:
{% block content %}
<form method="post">
<div class="sign-card">
<h3>Signup</h3>
{% csrf_token %}
<div class="input-div">
<label for="{{ form.name.id_for_label }}">Username:</label>
{{ form.name }}
</div>
<div class="input-div">
<label for="{{ form.email.id_for_label }}">Email:</label>
{{ form.email }}
</div>
<div class="input-div">
<label for="{{ form.password.id_for_label }}">Password:</label>
{{ form.password }}
</div>
<div class="input-div">
<label for="{{ form.password.id_for_label }}">Confirm Password:</label>
{{ form.confirm_password }}
</div>
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% endif %}
<button type="submit" class="btn">Sign up</button>
<p>Already have account? Log In</p>
</div>
</form>
{% endblock %}
My views.py:
def signup(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('name')
password = form.cleaned_data.get('password')
email = form.cleaned_data.get('email')
user = authenticate(username=username, password=password, email=email)
login(request, user)
return redirect('index')
else:
form = SignUpForm()
return render(request, 'registration/signup.html', {'form': form})
The problem I'm facing is that <div class="alert alert-danger"> doesn't work properly. It prints the text and makes it bold, but I have no CSS styling for it (like here, for example: https://www.csestack.org/display-messages-form-submit-django/). I don't want to use Django messages, neither change my code in views.py. How can I fix it? If there is no way to fix it without this changes, so, how can I fix the problem fixing my views.py?
Thanks a lot for your answers.
Actually, you are missing the css file to interpret the alert-danger class.
You can either manually write css for it or include some css library like bootstrap.
You can do something like below in your code: In <head> tag
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
</head>
It should work fine then.

Django from is not being past into html template

As in the question title "{{form}}" from is not being loaded into html template I checked by previous projects I have almost the same code, differences are required fields, naming etc. mechanic is the same.
In those projects registration function works perfectly here it's not even throwing an error just don't display anything.
No wonder what might be wrong in here.
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import Profile
class RegistrationForm(UserCreationForm):
email = forms.EmailField(max_length=60, help_text="Required field")
class Meta:
model = Profile
fields = ["email", "username", "password", "password2", "calories_plan", "diet_type"]
views.py
def registration_view(request):
context = {}
if request.POST:
form = RegistrationForm(request.POST)
if form.is_valid():
email = form.cleaned_data.get("email")
password = form.cleaned_data.get("password")
new_account = authenticate(email=email, password=password)
login(request, new_account)
else:
context["registration_form"] = form
else:
form = RegistrationForm()
context["registration_form"] = form
return render(request, "Account/registration.html", context)
html template
{% extends 'main.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="post">
{% csrf_token %}
<fieldset class="form-group">
<legend class=border-bottom mb-4>Join today
{{ form }}
</legend>
</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 href="#" class="ml-2">
Log In
</a>
</small>
</div>
</div>
{% endblock %}
And how it looks in browser.
You're passing 'registration_form' to the context, but in template you are calling {{ form }}.
Replace:
{{ form }}
with:
{{ registration_form }}

Why won't my UserCreationForm render in chronological order?

I want the form to show
Username
Email
Password
Password(2)
At the moment, it is showing
Username
Password
Password (2)
Email
I am trying to follow this tutorial https://www.youtube.com/watch?v=q4jPR-M0TAQ.
I have looked at the creators notes on Github but that has not helped.
I have double checked my code and cannot see any daft typos.
Can anyone provide any insight?
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import UserRegisterForm
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Account created for {username}!')
return redirect ('blog-home')
else:
form = UserRegisterForm()
return render(request, 'users/register.html', {'form':form})
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% 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 }}
</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="#">Sign In</a>
</small>
</div>
</div>
{% endblock content %}
you can customize the look and order of the form by this method, create a new template in the account/ template directory, name it register.html, and make it look as follows:
{% extends "base.html" %}
{% block title %}Create an account{% endblock %}
{% block content %}
<h1>Create an account</h1>
<p>Please, sign up using the following form:</p>
<form action="." method="post">{% csrf_token %}
{{ form.username }}
{{ form.other_fields_as_you_like }}
<p><input type="submit" value="Create my account"></p>
</form>
{% endblock %}

django form: CheckboxSelectMultiple's id_for_label does not work

I want to customize my label style, so I overwrite {{ form }} in my html template with a for loop through all choices. But I found I lost label 'for' attribute and 'id' of the input for each choice after using for loop.
Old codes:
html template:
{% block form %}
<button class="checker">Uncheck all</button> <button class="allChecker">Check all</button>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
<br/>
<input type="submit" value="Submit">
</form>
{% endblock %}
my form:
class RerunForm(forms.Form):
items = ItemStatus(
queryset=models.Container.objects.none(),
widget=forms.CheckboxSelectMultiple(attrs=dict(checked='')),
help_text="Select requirements/objectives that you want to rerun.",
)
def __init__(self, rerunqueryset, *args, **kwargs):
super(RerunForm, self).__init__(*args, **kwargs)
self.fields['items'].queryset = rerunqueryset
class ItemStatus(models.ModelMultipleChoiceField):
def label_from_instance(self, obj):
if '_' not in obj.name:
return "{} ({})".format(obj.name.replace('-r1', '').replace('-s1', ''), obj.state)
else:
return ". . . {} ({})".format(obj.name.replace('-r1', ''), obj.state)
New Codes:
html template:
{% block form %}
<button class="checker">Uncheck all</button> <button class="allChecker">Check all</button>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<ul id="id_items">
{% for value, label, item in form.items.field.choices %}
<li>
<label for="{{ form.items.id }}">
<input type="checkbox" value={{ value }} name="items" id="{{ form.items.auto_id }}">
<span class="listItem-{{item.state}}">{{ label }}</span>
</label>
</li>
{% endfor %}
</ul> <br/>
<input type="submit" value="Submit">
</form>
{% endblock %}
new form:
class RerunForm(forms.Form):
items = ItemStatus(
queryset=models.Container.objects.none(),
widget=forms.CheckboxSelectMultiple(attrs=dict(checked='')),
help_text="Select requirements/objectives that you want to rerun.",
)
def __init__(self, rerunqueryset, *args, **kwargs):
super(RerunForm, self).__init__(*args, **kwargs)
self.fields['items'].queryset = rerunqueryset
class ItemStatus(models.ModelMultipleChoiceField):
def label_from_instance(self, obj):
if '_' not in obj.name:
return "{} ({})".format(obj.name.replace('-r1', '').replace('-s1', ''), obj.state)
else:
return ". . . {} ({})".format(obj.name.replace('-r1', ''), obj.state)
def _get_choices(self):
if hasattr(self, '_choices'):
return self._choices
return CustomModelChoiceIterator(self)
choices = property(_get_choices,
MultipleChoiceField._set_choices)
class CustomModelChoiceIterator(models.ModelChoiceIterator):
def choice(self, obj):
# return super(CustomModelChoiceIterator, self).choice(obj)
return (self.field.prepare_value(obj),
self.field.label_from_instance(obj),
obj)
The old codes gave me <label for='id_items_1'><input ... id='id_items_1>... when I inspect, but the new codes only gave me <label><input ...> without for and id attributes.
I tried adding <label for="{{ form.items.id_for_label }}> in html, no luck.
then <label for="{{ form.items.auto_it }}> gave me <label for="id_items">, but not differentiate choice from one to another. Please help on how to add 'id_items_0', 'id_items_1',... as label 'for' and input 'id' to each of my choice in html?
I also attached what it looks like now with new codes.
web-page and inspect results with new codes

How to call a function from a html button - Django

What I'm trying to do is execute a function when the user clicks the "add to cart" button, the product displayed on the screen will be added to the cart model. So far i've figured out how to add objects to the cart from the shell. What i don't know is how to call a python function with html and how to pass the object to it. Thank you in advance.
my template.html:
{% extends 'templates/header.html' %}
<title>{% block head_title %}{{ object.name }} - {{ block.super }}{% endblock head_title %}</title>
{% block head %}
{{ block.super }}
{% load staticfiles %}
<link rel = "stylesheet" href = "{% static 'css/products_detail.style.css' %}" type = "text/css"/>
{% endblock head %}
{% block content %}
<div id='Product-Page'>
<p>{{ object.name }}</p>
<hr>
<div id='Product-Image'>
<img src='{{ object.image.url }}' alt='{{ object.image.name }}'/>
</div>
<div id='Product-Details'>
<p id='Product-Name'>{{ object.name }}</p>
<p id='Product-Description'><small>{{ object.description }}</small></p>
</div>
<div id='Product-Buy'>
<p id='Product-Price'>{{ object.price }} лв.</p>
<p id='Product-Quantity'>{{ object.quantity }} </p>
<form class='Product-Form' method='post' action='#'>
{% csrf_token %}
<input class='Product-Button' type='submit' value='Buy Now'>
</form>
<form class='Product-Form' method='get' action=''>
{% csrf_token %}
<input class='Product-Button' type='submit' value='Add to cart'>
</form>
</div>
<hr>
</div>
{% endblock content%}
my view:
class ProductDetailView(DetailView):
template_name = 'products/products_detail.html'
def get_object(self, *args, **kwargs):
slug = self.kwargs.get('slug')
return get_object_or_404(Product, slug=slug)
You can add hidden inputs to each form (both of which should be POST methods, not GET) then add a post method to your view. Something like:
<form class='Product-Form' method='post'>
{% csrf_token %}
<input name="buy-now" hidden>
<input name="pk" value="{{ object.pk }}" hidden>
<button type="submit" class="btn">Buy Now</button>
</form>
<form class='Product-Form' method='post'>
{% csrf_token %}
<input name="add-to-cart" hidden>
<input name="pk" value="{{ object.pk }}" hidden>
<button type="submit" class="btn">Add to cart</button>
</form>
Then in your view:
class ProductDetailView(DetailView):
template_name = 'products/products_detail.html'
def get_object(self, *args, **kwargs):
slug = self.kwargs.get('slug')
return get_object_or_404(Product, slug=slug)
def post(self, request, *args, **kwargs):
name = request.POST.get("pk")
product = Product.objects.get(pk=pk)
if "buy-now" in request.POST:
#Do something to buy.
print('buy now ' + product.name)
elif "add-to-cart" in request.POST:
#Add to cart.
print('add to cart ' + product.name)
return redirect('home')
Or you can do it via AJAX if you don't want to reload the page.