I try to add a validation state like "this already exist." (like registration form, see picture) just under my form input.
But when I submit my form i'v this error 'UNIQUE constraint failed'
this is my code
model
class Company(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
siret = models.CharField(max_length=50, unique=True)
forms
class CheckoutForm(forms.Form):
siret = forms.CharField(required=True, widget=forms.TextInput(attrs={'placeholder': 'Ton SIRET'}))
class Meta:
model = Company
fields = ('siret')
def clean(self):
siret = cleaned_data.get('siret')
if siret:
raise forms.ValidationError("This siret exist.")
else:
return siret
view
def post(self, request, *args, **kwargs):
form = CheckoutForm(self.request.POST)
if form.is_valid():
siret = form.cleaned_data.get('siret')
company = Company(
user = self.request.user,
siret = siret,
)
company.save()
context = {
'company': company,
}
return redirect("core:payment")
else:
messages.info(self.request, "Please fill in the shipping form properly")
return redirect("core:checkout")
template
{% load crispy_forms_tags %}
<main>
<div class="container wow fadeIn">
<h2 class="my-5 h2 text-left">Checkout form</h2>
<div class="row">
<div class="col-md-8 mb-4">
<div class="card">
<form method="post" class="card-body">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-primary" id="checkout-button" data-secret="{{ session_id }}">
Checkout
</button>
</form>
</div>
</div>
Thanks a lot
you have to add errors_messages to your email field like this:
email = models.EmailField(
_('email address'),
blank=True,
unique=True,
null=True,
error_messages={
'unique': _("A user with that email address already exists."),
}
)
Related
I am adding a simple review function on my Social platform Django project, where Users can write a review on another user's profile. But after posting the review, it's only showing on the profile page of the user that I'm currently signed in to.
This is my models.py
` class Review(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
reviewmsg = models.TextField(null=True, blank=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.reviewmsg)`
views.py
` def userProfile(request, pk):
user = User.objects.get(id=pk)
rooms = user.room_set.all()
reviews = user.review_set.all()
if request.method == 'POST':
review = Review.objects.create(
user=request.user,
reviewmsg=request.POST.get('reviewmsg')
)
return redirect('user-profile', pk=user.id)
context = {'user':user, 'rooms':rooms, 'reviews':reviews}
return render(request, 'pages/profile.html', context)`
excerpt from my profile page template
` <div>
{% for review in reviews %}
<div class="comment-sect" style="margin-top: 0.5rem;">
<div class="comment-photo" style="margin: auto;">
<a href="{% url 'user-profile' review.user.id %}">
<div class="profile-photo">
<img src="{{review.user.avatar.url}}">
</div>
</a>
</div>
<div class="comment-info" style="width: 300px;">
<small>#{{review.user}}</small>
<small>{{review.created|timesince}} ago </small>
<p style="margin-bottom:0;">{{review.reviewmsg}}</p>
</div>
</div><!--end of comment-sect-->
{% endfor %}
<div class="comment-form" style="margin-top: 0.5rem; text-align:center;">
<form method="POST" action="">
{% csrf_token %}
<div>Submit a Review
<input type="text" name="reviewmsg" placeholder="What do you think about this User?"/>
</div>
</form>
</div>`
EDITED
As mentioned by #lain Shelvington, I agree that I need to add another ForeignKey to my models. I tried updating the models.py to:
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Review(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
profile = models.ForeignKey(Profile, on_delete=models.SET_NULL, null=True)
reviewmsg = models.TextField(null=True, blank=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.reviewmsg)
and views.py to:
user = User.objects.get(id=pk)
rooms = user.room_set.all()
reviews = user.review_set.all()
if request.method == 'POST':
review = Review.objects.create(
user=request.user,
profile=user,
reviewmsg=request.POST.get('reviewmsg')
)
return redirect('user-profile', pk=user.id)
context = {'user':user, 'rooms':rooms, 'reviews':reviews}
return render(request, 'pages/profile.html', context)
but ended up with error:
ValueError at /profile/7/
Cannot assign "<User: celeste>": "Review.profile" must be a "Profile" instance
I have a login page and register page where a user can create an account and login to his account, the problem is that: when I login with different user it's gives me everything that is created by the superuser or other user's instead of showing an empty page that could let me create fresh Album and Primary for the new user, Just like Facebook when you create an account and login it's will shows you an empty page in your Account. No friends no new Post and so on. How can i do this???
the login views:
def login(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = auth.authenticate(username=username, password=password)
if user is not None:
auth.login(request, user)
return redirect('home')
else:
messages.info(request, 'Invalid Credential')
return redirect('login')
else:
return render(request, 'login.html')
the register view:
def register(request):
if request.method == 'POST':
username = request.POST['username']
email = request.POST['email']
password = request.POST['password']
password2 = request.POST['password2']
if password == password2:
if User.objects.filter(email=email).exists():
messages.info(request, 'Email or user name Already taking')
return redirect('register')
elif User.objects.filter(username=username).exists():
messages.info(request, 'username is taken')
return redirect('register')
else:
user = User.objects.create_user(username=username, email=email,
password=password)
user.save();
return redirect('login')
else:
messages.info(request, 'Password Not Match')
return redirect('register')
return redirect ('/')
else:
return render(request, 'signup.html')
the models:
class Album(models.Model):
image = models.ImageField(null=False, blank=False)
name = models.CharField(max_length=100, null=False, blank=False)
def __str__(self):
return self.name
class Primary(models.Model):
profilePicture = models.ImageField(blank=False, null=False)
firstName = models.CharField(max_length=25, blank=False, null=False)
sureName = models.CharField(max_length=25, blank=False, null=False)
lastName = models.CharField(max_length=25, blank=False, null=False)
address = models.CharField(max_length=50, blank=False, null=False)
classOf = models.CharField(max_length=20, blank=False, null=False)
yearOfGraduations = models.CharField(max_length=20, blank=False, null=False)
hobbies = models.TextField(blank=False, null=False)
dateOfBirth = models.CharField(max_length=20)
year = models.ForeignKey(Album, on_delete=models.CASCADE)
def __str__(self):
return self.firstName
the Album Templates:
<div class="container">
<div class="row">
<div class="col-md-3">
Create Album
</div>
<!--Albums-->
{% for my_album in albums %}
<div class="col-md-9">
<div class="card" style="width: 18rem;">
<img src="{{ my_album.image.url }}" alt="" class="card-img-top">
<div class="card-body">
<p>{{ my_album.name }}</p>
<br>
viewAlbum
</div>
</div>
</div>
{% endfor %}
</div>
</div>
the Album view:
def primary(request):
albums = Album.objects.all()
return render(request, 'primary.html', {'albums': albums})
the viewAlbum templates:
<div class="container">
<div class="row">
<div class="col">
Create Students
</div>
</div>
</div>
<br>
<div class="container">
<div class="row justify-content-center">
{% for prima in primaries %}
<div class="col">
<div class="card my-2" style="width: 18rem;">
<img src="{{ prima.profilePicture.url }}" alt="" class="card-img-top">
<div class="card-body">
<p>{{ prima.firstName }}</p>
<br>
view Students
</div>
</div>
</div>
</div>
{% endfor %}
</div>
the viewAlbum view:
def viewAlbum(request, pk):
post = get_object_or_404(Album, id=pk)
my_album = Album.objects.get(id=pk)
primaries = Primary.objects.filter(year_id=my_album.pk)
return render(request, 'viewAlbum.html', {'primaries': primaries, 'post':post,
'my_album':my_album})
you could add a ForeignKey to the Album:
class Album(models.Model):
image = models.ImageField(null=False, blank=False)
name = models.CharField(max_length=100, null=False, blank=False)
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
then save each album with the user creating it.
And then filter the album in the view:
def primary(request):
albums = Album.objects.filter(user=request.user)
return render(request, 'primary.html', {'albums': albums})
ok basically, users on my website can create blogposts. But I do not want to use unique = True because that'll mean that user1 cannot create a post that has the same title as user2.
I want to make it such that user1 can create a post that has the same title as user2 BUT user1 CANNOT create another post with the same name as any existing post that USER1 has previously created.
Meaning user 1 can have a blogpost title "hello" and user 2 can also have a blogpost "hello"
but user 1 cannot have 2 blogpost with the same title 'hello'
Ok i think this is clear enough^....if I use unique = true, this would be too much, so how can I customise that such that it only applies to the user's post? Thanks!
models.py
class BlogPost(models.Model):
title = models.CharField(max_length=50, null=False, blank=False, unique=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
slug = models.SlugField(blank=True, unique=True)
class Account(AbstractBaseUser):
email = models.EmailField(verbose_name="email", max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
forms.py
class CreateBlogPostForm(forms.ModelForm):
class Meta:
model = BlogPost
fields = ['chief_title']
html
<form class="create-form" method="post" enctype="multipart/form-data">{% csrf_token %}
<div class="form-group">
<label for="id_title">Title</label>
<input class="form-control" type="text" name="title" id="id_title" placeholder="Title" required autofocus>
</div>
<button class="submit-button btn btn-lg btn-primary btn-block" type="submit">Submit</button>
</form>
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}
views.py
def create_blog_view(request):
context = {}
user = request.user
if request.method == 'POST':
form = CreateBlogPostForm(request.POST or None, request.FILES or None)
if form.is_valid():
obj.save()
return redirect('HomeFeed:main')
else:
context['form'] = form
return render(request, "HomeFeed/create_blog.html", context)
you could use a unique constraint, this allows 2 fields to interact and be unique so you could have a post name that can only be used once per user
I changed ModelChoiceField to be shown as a TextInput.
I have a field named 'filename' of this type: models.ForeignKey('Filename', on_delete=models.SET_NULL, null=True, blank=True) in a class as follow:
models.py
class Event(models.Model):
name = models.CharField('Name', max_length=100, blank=True, default='')
filename = models.ForeignKey('Filename', on_delete=models.SET_NULL, null=True, blank=True)
class Filename(models.Model):
name = models.CharField('Name', max_length=50)
def __str__(self):
return self.nome
This is part of my 'forms.py' I use show form in frontend after defining the template (myappname/templates/myappname/event_edit.html)
forms.py
class EventEditForm(forms.ModelForm):
def __init__(self, data=None, *args, **kwargs):
if data is not None:
data = data.copy()
if data['filename']:
f, f_created = Filename.objects.get_or_create(nome=data['filename'])
data['filename'] = m.id
super(EventEditForm, self).__init__(data=data, *args, **kwargs)
self.fields['filename'] = forms.ModelChoiceField(queryset=Filename.objects.all(), widget=forms.TextInput(attrs={'class': 'form-control', 'value':self.instance.filename}))
self.fields['filename'].required = False
class Meta:
model = Event
fields = ['name', 'filename']
and this is my event_edit.html:
<form method="post" class="form-horizontal">
{% csrf_token %}
{% for field in event_form %}
<div class="form-group form-group-lg">
<label for="{{ field.id_for_label }}" class="col-sm-2 control-label">{{field.label}}</label>
<div class="col-sm-6">
{{ field }}
</div>
<div class="col-sm-4">
{{ field.errors }}
</div>
</div>
{% endfor %}
<div class="form-group">
<div class="col-sm-10">
<button type="submit" class="btn btn-primary btn-lg center-block">Save</button>
</div>
</div>
</form>
The problem is that if I override ModelChoiceField to be a TextInput the 'filename' field shows id instead of showing field name.
Otherwise, If I leave it as a Choice Field it correctly shows value instead of id.
How can I solve this issue?
Based on your comments and the code in EventEditForm, you want a form that will:
display the Event.name and the linked Filename.name
use the submitted name to update Event.name
use the submitted filename to lookup or create a Filename and update Event.filename
This should work:
class EventEditForm(forms.ModelForm):
"""
Calling form.save() will:
* update the Event.name
* update the Event.filename with a Filename instance
found or created using the supplied name
"""
fname = forms.CharField(
label='Filename',
required=False,
widget=forms.TextInput(attrs={'class': 'form-control'}),
)
class Meta:
model = Event
fields = ['name',]
widgets = {
'name': forms.TextInput(attrs={'class': 'form-control'}),
}
def __init__(self, *args, **kwargs):
super(EventEditForm, self).__init__(*args, **kwargs)
self.initial['fname'] = self.instance.filename
def save(self, commit=True):
instance = super(EventEditForm, self).save(commit=False)
cleaned_fname = self.cleaned_data['fname']
if cleaned_fname:
f, f_created = Filename.objects.get_or_create(name=cleaned_fname)
instance.filename = f
else:
instance.filename = None
if commit:
instance.save()
return instance
I'm getting an issue with my Django form validation. I would like to display form errors and make all fields required. I don't know why my fields can accept blank while blank is not defined in my model file.
This is my model :
class Customer(models.Model):
email = models.CharField(max_length=150, verbose_name=_('e-mail'), null=False)
first_name = models.CharField(max_length=70, verbose_name=_('first name'), null=False)
last_name = models.CharField(max_length=70, verbose_name=_('last name'), null=False)
country = models.ForeignKey(Country, verbose_name=_('country'))
institution = models.CharField(max_length=255, verbose_name=_('institution'), null=True)
creation_date = models.DateTimeField(auto_now_add=True, verbose_name=_('creation date'), null=False)
modification_date = models.DateTimeField(auto_now=True, verbose_name=_('modification date'), null=False)
class Meta:
verbose_name = _('customer')
verbose_name_plural = _('customer')
def __str__(self):
return f"{self.email}"
This is my form :
class CustomerForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(CustomerForm, self).__init__(*args, **kwargs)
self.fields['country'].empty_label = _('Select a country')
self.fields['country'].queryset = self.fields['country'].queryset.order_by(
'name')
for key in self.fields:
self.fields[key].required = True
class Meta:
model = Customer
fields = ['email', 'first_name', 'last_name', 'country', 'institution']
widgets = {
'email': forms.TextInput(attrs={'placeholder': _('name#example.com')}),
'first_name': forms.TextInput(attrs={'placeholder': _('First Name')}),
'last_name': forms.TextInput(attrs={'placeholder': _('Last Name')}),
'institution': forms.TextInput(attrs={'placeholder': _('Agency, company, academic or other affiliation')}),
}
You can find here my view with Django CBV :
class HomeView(CreateView):
""" Render the home page """
template_name = 'app/index.html'
form_class = CustomerForm
def get_context_data(self, **kwargs):
kwargs['document_list'] = Document.objects.all().order_by('publication__category__name')
return super(HomeView, self).get_context_data(**kwargs)
def post(self, request, *args, **kwargs):
if request.method != 'POST':
return HttpResponseRedirect(self.get_success_url())
form = self.form_class(request.POST)
email = request.POST['email']
country_id = request.POST['country']
country = Country.objects.get(id=country_id)
for checkbox in request.POST.getlist('DocumentChoice'):
document = Document.objects.get(id=checkbox)
token = self.gen_token(email, document.edqm_id)
Download.objects.create(email=email, country=country, pub_id=checkbox, token=token,
expiration_date=now + timedelta(minutes=10))
if not form.is_valid():
print('form invalid')
continue
return HttpResponseRedirect(self.get_success_url())
And finally my template :
{% extends "publication/base_backend.html" %}
{% load staticfiles %}
{% load i18n %}
{% load crispy_forms_tags %}
{% block main %}
<form method="post" id="customerform" novalidate>
{% csrf_token %}
<h3>{% trans 'Your information' %}</h3>
<hr>
<div class="col-sm-12 col-md-12 col-lg-12">
{{ form.email|as_crispy_field:"bootstrap" }}
</div>
<br />
<br />
<br />
<br />
<div class="alert alert-info col-sm-12 col-md-12 col-lg-12" role="alert">
<small>{% trans "The fields below are optional if you have already requested a publication:" %}</small>
</div>
<div class="col-sm-5 col-md-5 col-lg-5">
{{ form.first_name|as_crispy_field:"bootstrap" }}<br>
{{ form.country|as_crispy_field:"bootstrap" }}
</div>
<div class="col-sm-5 col-md-5 col-lg-5 col-sm-offset-2 col-md-offset-2 col-lg-offset-2">
{{ form.last_name|as_crispy_field:"bootstrap" }}<br>
{{ form.institution|as_crispy_field:"bootstrap" }}
</div>
<div class="col-md-12">
<br />
<br />
</div>
<input type="submit" class="btn btn-default" value="{% trans 'Save' %}"/>
{% trans 'Cancel' %}
</form>
Issues :
According to required fields, I don't know why my form doesn't display missing values errors when I want to submit it.
I have to display fields as shown in my template because I have to make bootstrap design.
In order to display form errors, I have to write {{form.email.errors}} for example but nothing appears.
Thank you by advance