réservation possible

This commit is contained in:
Ruidy Nemausat 2019-11-07 15:07:42 +01:00
parent 16f483a9de
commit 1a4365e7a0
11 changed files with 272 additions and 91 deletions

View file

@ -60,12 +60,14 @@ Le visiteur doit pouvoir :
* témoignage
## TO DO
* remplir les détails des logements et ajouter les photos dynamiquement
* afficher le logo
* Gestion du calendrier
* Ajout du formulaire de réservation sur la page détail
* Ajouter la page de paiement
* Les photos de la page à propos
* Ajouter un bouton réserver maintenant avant le résumé => formulaire en bas
* formatter la page réservation
* Formatter la page de remerciement (expliquer la suite)
* designer la page d'accueil
* remplir les détails des logements et ajouter les photos dynamiquement
* Les photos de la page à propos
* écrire les mentions légales
* Gestion du calendrier
* Ajout page/module de paiement
* changer la couleur des liens hypertextes
* changer l'adresse de l'admin

35
rental/forms.py Normal file
View file

@ -0,0 +1,35 @@
from django import forms
from .models import Reservation, Place, Guest
from phonenumber_field.modelfields import PhoneNumberField
class ReservationForm(forms.Form):
PLACES=(('T2','T2'), ('T3','T3'),)
name = forms.CharField(
label="",
max_length=100,
min_length=4,
widget=forms.TextInput(attrs={'class': 'form-control form-control-lg form-control-a', 'placeholder': 'Nom *'}),
required=True)
email = forms.EmailField(
label = '',
widget=forms.EmailInput(attrs={'class': 'form-control form-control-lg form-control-a', 'placeholder': 'Email *'}),
required=True
)
phone = forms.CharField(
label='',
max_length=100,
min_length=4,
widget=forms.TextInput(attrs={'class': 'form-control form-control-lg form-control-a', 'placeholder': 'Téléphone *'}),
required=True)
place = forms.ChoiceField(
label = '',
widget=forms.Select(attrs={'class': 'form-control form-control-lg form-control-a'}),
required=True,
choices=PLACES)
message = forms.CharField(
label='',
max_length=100,
min_length=4,
widget=forms.Textarea(attrs={'class': 'form-control', 'cols': '45', 'rows':'8', 'placeholder': 'Message *'}),
required=True)

View file

@ -12,9 +12,13 @@ class Place(models.Model):
name=models.CharField(max_length=10, unique=True)
pictures=models.ImageField(upload_to="uploads/",null=True,blank=True)
description=models.TextField(blank=True)
info=models.TextField(blank=True)
subname=models.CharField(max_length=100, blank=True)
tagline=models.CharField(max_length=100, blank=True)
price=models.DecimalField(max_digits=6, decimal_places=2, null=True)
surface=models.IntegerField(null=True,blank=True)
beds=models.IntegerField(null=True,blank=True)
max_occupation=models.IntegerField(null=True,blank=True)
class Guest(models.Model):
@ -38,6 +42,7 @@ class Reservation(models.Model):
place=models.OneToOneField(Place,on_delete=models.CASCADE)
guest=models.ForeignKey(Guest,on_delete=models.CASCADE)
message=models.TextField(blank=True)
class Testimonial(models.Model):

View file

@ -3,6 +3,10 @@ body {
color: #555555;
}
html {
scroll-behavior: smooth;
}
h1,
h2,
h3,
@ -121,6 +125,10 @@ a:hover {
/*------/ Bg Image /------*/
.logo {
height: 60px;
}
.bg-image {
background-repeat: no-repeat;
background-attachment: fixed;

View file

@ -126,7 +126,7 @@
</button>
<a class="navbar-brand text-brand" href="{% url 'rental:index' %}">
<!-- <img class="img-fluid" src="{% static 'img/apple-touch-icon.png' %}" alt="villafleurie_logo" > -->
<img class="logo" src="{% static 'img/apple-touch-icon.png' %}" alt="villafleurie_logo" >
Villa<span class="color-b">Fleurie</span>
</a>
<button type="button" class="btn btn-link nav-search navbar-toggle-box-collapse d-md-none" data-toggle="collapse"
@ -166,8 +166,9 @@
<div class="col-sm-12 col-md-6">
<div class="widget-a">
<div class="w-header-a">
<!-- <img class="img-fluid" src="{% static 'img/apple-touch-icon.png' %}" alt="villafleurie_logo" > -->
<h3 class="w-title-a text-brand">VillaFleurie</h3>
<a class="navbar-brand text-brand" href="{% url 'rental:index' %}">
<h3 class="w-title-a text-brand">Villa<span class="color-b">Fleurie</span></h3>
</a>
</div>
<div class="w-body-a">
<p class="w-text-a color-text-a">

View file

@ -19,7 +19,7 @@
<a href="{% url 'rental:index' %}">Accueil</a>
</li>
<li class="breadcrumb-item">
<a href="{% url 'rental:detail_place' place_name=place.name %}">Hébergements</a>
<a href="{% url 'rental:list_place' %}">Hébergements</a>
</li>
<li class="breadcrumb-item active" aria-current="page">
{{ place.name }}
@ -56,7 +56,7 @@
<span class="ion-money"></span>
</div>
<div class="card-title-c align-self-center">
<h5 class="title-c"> {{ place.price }}</h5>
<h5 class="title-c"> {{ place.price }} </h5>
</div>
</div>
</div>
@ -70,39 +70,27 @@
</div>
<div class="summary-list">
<ul class="list">
<li class="d-flex justify-content-between">
<strong>Property ID :</strong>
<span>1134</span>
</li>
<li class="d-flex justify-content-between">
<strong>Localisation :</strong>
<span>Le Gosier, Guadeloupe</span>
</li>
<li class="d-flex justify-content-between">
<strong>Type :</strong>
<span>House</span>
</li>
<li class="d-flex justify-content-between">
<strong>Status :</strong>
<span>Disponible</span>
</li>
<li class="d-flex justify-content-between">
<strong>Surface :</strong>
<span>340m
<span>{{ place.surface}}
<sup>2</sup>
</span>
</li>
<li class="d-flex justify-content-between">
<strong>Lits :</strong>
<span>4</span>
<span>{{ place.beds }}</span>
</li>
<li class="d-flex justify-content-between">
<strong>Baths:</strong>
<span>2</span>
</li>
<li class="d-flex justify-content-between">
<strong>Garage:</strong>
<span>1</span>
<strong>Nombre de voyageurs maximum :</strong>
<span>{{ place.max_occupation}}</span>
</li>
</ul>
</div>
@ -118,10 +106,10 @@
</div>
<div class="property-description">
<p class="description color-text-a">
{{ place.description}}
{{ place.description |safe}}
</p>
<p class="description color-text-a no-margin">
{{ place.description}}
{{ place.info |safe}}
</p>
</div>
<div class="row section-t3">
@ -149,26 +137,26 @@
</div>
<div class="col-md-10 offset-md-1">
<ul class="nav nav-pills-a nav-pills mb-3 section-t3" id="pills-tab" role="tablist">
<li class="nav-item">
<!-- <li class="nav-item">
<a class="nav-link active" id="pills-video-tab" data-toggle="pill" href="#pills-video" role="tab"
aria-controls="pills-video" aria-selected="true">Video</a>
</li>
</li> -->
<li class="nav-item">
<a class="nav-link" id="pills-map-tab" data-toggle="pill" href="#pills-map" role="tab" aria-controls="pills-map"
<a class="nav-link active" id="pills-map-tab" data-toggle="pill" href="#pills-map" role="tab" aria-controls="pills-map"
aria-selected="false">Localisation</a>
</li>
</ul>
<div class="tab-content" id="pills-tabContent">
<div class="tab-pane fade show active" id="pills-video" role="tabpanel" aria-labelledby="pills-video-tab">
<!-- <div class="tab-pane fade show active" id="pills-video" role="tabpanel" aria-labelledby="pills-video-tab">
<iframe src="https://player.vimeo.com/video/73221098" width="100%" height="460" frameborder="0"
webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
</div>
<div class="tab-pane fade" id="pills-plans" role="tabpanel" aria-labelledby="pills-plans-tab">
</div> -->
<!-- <div class="tab-pane fade " id="pills-plans" role="tabpanel" aria-labelledby="pills-plans-tab">
<img src="{% static 'img/plan2.jpg' %}" alt="" class="img-fluid">
</div>
<div class="tab-pane fade" id="pills-map" role="tabpanel" aria-labelledby="pills-map-tab">
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3022.1422937950147!2d-73.98731968482413!3d40.75889497932681!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x89c25855c6480299%3A0x55194ec5a1ae072e!2sTimes+Square!5e0!3m2!1ses-419!2sve!4v1510329142834"
width="100%" height="460" frameborder="0" style="border:0" allowfullscreen></iframe>
</div> -->
<div class="tab-pane fade show active" id="pills-map" role="tabpanel" aria-labelledby="pills-map-tab">
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3831.2547874074585!2d-61.48954768556058!3d16.207335988795712!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x8c134f148764f5d5%3A0x981bb218cee8b16c!2sVillaFleurie!5e0!3m2!1sfr!2sde!4v1573125589212!5m2!1sfr!2sde"
width="100%" height="460" frameborder="0" style="border:0;" allowfullscreen=""></iframe>
</div>
</div>
</div>
@ -180,7 +168,7 @@
</div>
</div>
</div>
<div class="row">
<div id="reservation"class="row">
<div class="col-md-6 col-lg-4">
<img src="{% static 'img/agent-4.jpg' %}" alt="" class="img-fluid">
</div>
@ -243,29 +231,12 @@
</div>
<div class="col-md-12 col-lg-4">
<div class="property-contact">
<form class="form-a">
<form class="form-a" method='post'>
<div class="row">
<div class="col-md-12 mb-1">
<div class="form-group">
<input type="text" class="form-control form-control-lg form-control-a" id="inputName"
placeholder="Nom *" required>
</div>
</div>
<div class="col-md-12 mb-1">
<div class="form-group">
<input type="email" class="form-control form-control-lg form-control-a" id="inputEmail1"
placeholder="Email *" required>
</div>
</div>
<div class="col-md-12 mb-1">
<div class="form-group">
<textarea id="textMessage" class="form-control" placeholder="Message *" name="message" cols="45"
rows="8" required></textarea>
</div>
</div>
<div class="col-md-12">
<button type="submit" class="btn btn-a">Envoyer</button>
</div>
{% csrf_token %}
{{ form.as_p }}
<p><button type="submit" class="btn btn-a">Envoyer</button></p>
</div>
</form>
</div>

View file

@ -0,0 +1,4 @@
{% extends 'rental/base.html' %}
{% load static %}
<h1>merci</h1>

View file

@ -31,6 +31,91 @@
</div>
</section>
<!--/ Intro Single End /-->
<section class="property-single nav-arrow-b">
<div class="container">
<div class="row">
<div class="col-md-12">
<div id="reservation"class="row">
<div class="col-md-6 col-lg-4">
<img src="{% static 'img/agent-4.jpg' %}" alt="" class="img-fluid">
</div>
<div class="col-md-6 col-lg-4">
<div class="property-agent">
<h4 class="title-agent">Nilka</h4>
<p class="color-text-a">
Nulla porttitor accumsan tincidunt. Vestibulum ac diam sit amet quam vehicula elementum sed sit amet
dui. Quisque velit nisi,
pretium ut lacinia in, elementum id enim.
</p>
<ul class="list-unstyled">
<li class="d-flex justify-content-between">
<strong>Phone:</strong>
<span class="color-text-a">(222) 4568932</span>
</li>
<li class="d-flex justify-content-between">
<strong>Mobile:</strong>
<span class="color-text-a">777 287 378 737</span>
</li>
<li class="d-flex justify-content-between">
<strong>Email:</strong>
<span class="color-text-a">annabella@example.com</span>
</li>
<li class="d-flex justify-content-between">
<strong>Skype:</strong>
<span class="color-text-a">Annabela.ge</span>
</li>
</ul>
<div class="socials-a">
<ul class="list-inline">
<li class="list-inline-item">
<a href="#">
<i class="fa fa-facebook" aria-hidden="true"></i>
</a>
</li>
<li class="list-inline-item">
<a href="#">
<i class="fa fa-twitter" aria-hidden="true"></i>
</a>
</li>
<li class="list-inline-item">
<a href="#">
<i class="fa fa-instagram" aria-hidden="true"></i>
</a>
</li>
<li class="list-inline-item">
<a href="#">
<i class="fa fa-pinterest-p" aria-hidden="true"></i>
</a>
</li>
<li class="list-inline-item">
<a href="#">
<i class="fa fa-dribbble" aria-hidden="true"></i>
</a>
</li>
</ul>
</div>
</div>
</div>
<div class="col-md-12 col-lg-4">
<div class="property-contact">
<form class="form-a" method='post'>
<div class="row">
<div class="col-md-12 mb-1">
{% csrf_token %}
{{ form.as_p }}
<p><button type="submit" class="btn btn-a">Envoyer</button></p>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!--/ Contact Star /-->
<section class="contact">

View file

@ -7,6 +7,6 @@ app_name = 'rental'
urlpatterns = [
path('', views.Accueil.as_view(), name='index'),
path('hebergements/', views.ListeLocation.as_view(), name='list_place'),
path('<place_name>/', views.Location.as_view(), name='detail_place'),
# path('<place_name>/', views.location, name='detail_place'),
# path('<place_name>/', views.Location.as_view(), name='detail_place'),
path('<place_name>/', views.location, name='detail_place'),
]

View file

@ -3,14 +3,8 @@ from django.views.generic import ListView, DetailView, CreateView, UpdateView, D
from .models import Testimonial, Reservation, Guest, Place
from django.urls import reverse_lazy
from django.views.generic.base import TemplateView
# Réservation : dans le detail_place.html ajouter un formulaire (if method = post …)
# Paiement : payer
# Remerciement après loocation
# Contact
# À propos
# Légal & CGU
from.forms import ReservationForm
from django.db import IntegrityError
class Accueil(ListView):
@ -18,34 +12,107 @@ class Accueil(ListView):
template_name = 'rental/index.html'
context_object_name = 'places'
class ListeLocation(ListView):
model = Place
template_name = 'rental/list_place.html'
context_object_name = 'places'
class Location(DetailView):
model = Place
template_name = 'rental/detail_place.html'
context_object_name = 'place'
def get_object(self, queryset=None):
place_name = self.kwargs.get('place_name', None)
return get_object_or_404(Place, name=place_name)
def location(request, place_name):
place = get_object_or_404(Place, name=place_name)
context = {'place' : place}
if request.method == 'POST':
form = ReservationForm(request.POST)#, error_class=ParagraphErrorList)
if form.is_valid():
name = form.cleaned_data['name']
email = form.cleaned_data['email']
phone = form.cleaned_data['phone']
message = form.cleaned_data['message']
place_name = form.cleaned_data['place']
try:
guest = Guest.objects.filter(email=email)
if not guest.exists():
guest = Guest.objects.create(
email=email,
name=name
)
else:
guest = guest.first()
place = get_object_or_404(Place, name=place_name)
reservation = Reservation.objects.create(
guest=guest,
place=place,
message=message
)
context = {
'guest': guest,
'place': place
}
return render(request, 'rental/merci.html', context)
except IntegrityError:
form.errors['internal'] = "Une erreur interne est apparue. \
Merci de recommencer votre requête."
else:
form = ReservationForm()
context['form'] = form
context['errors'] = form.errors.items()
return render(request, 'rental/detail_place.html', context)
def reservation(request):
if request.method == 'POST':
form = ReservationForm(request.POST)#, error_class=ParagraphErrorList)
if form.is_valid():
name = form.cleaned_data['name']
email = form.cleaned_data['email']
phone = form.cleaned_data['phone']
message = form.cleaned_data['message']
place_name = form.cleaned_data['place']
try:
guest = Guest.objects.filter(email=email)
if not guest.exists():
guest = Guest.objects.create(
email=email,
name=name
)
else:
guest = guest.first()
place = get_object_or_404(Place, name=place_name)
reservation = Reservation.objects.create(
guest=guest,
place=place,
message=message
)
context = {
'guest': guest,
'place': place
}
return render(request, 'rental/merci.html', context)
except IntegrityError:
form.errors['internal'] = "Une erreur interne est apparue. Merci de recommencer votre requête."
else:
form = ReservationForm()
context = {'form' : form}
return render(request, 'rental/reservation.html', context)
# def location(request, place_name):
# place = Place.objects.get(name=place_name)
# context = {'place' : place}
# return render(request, 'rental/detail_place.html', context)
class Contact(TemplateView):
template_name = 'rental/contact.html'
class Reserver(TemplateView):
template_name = 'rental/reservation.html'
class Legal(TemplateView):
template_name = 'rental/legal.html'
def about(request):
context = {}
return render(request, 'rental/about.html', context)
class About(TemplateView):
template_name = 'rental/about.html'
def handler404(request, exception):
return render(request, 'store/404.html', status=404)
def handler500(request):
return render(request, 'store/500.html', status=500)

View file

@ -3,13 +3,16 @@ from django.urls import path
from django.conf import settings
from django.conf.urls import include, url
from rental import views
# from django.contrib.flatpages import views as flat_views
urlpatterns = [
path('admin/', admin.site.urls),
path('contact/', views.Contact.as_view(), name='contact'),
path('a-propos/', views.about, name='about'),
path('reservation/', views.Reserver.as_view(), name='reservation'),
path('a-propos/', views.About.as_view(), name='about'),
path('reservation/', views.reservation, name='reservation'),
path('legal/', views.Legal.as_view(), name='legal'),
path('', include('rental.urls', namespace='rental')),
]
handler404 = 'rental.views.handler404'
handler500 = 'rental.views.handler500'