I'm new to Django and I have a problem moving my stuff to the front end of my website.
I want to do fantasy-style website. My main page will display a list of NHL players. These players will be picked by the user and added to their team in order .
My problem is this: I want a popup-style modal to open when a user clicks a player on the main page. This modal would contain a confirmation before this specific player is added to the user's team.
Here is my player model:
class Player(models.Model):
name = models.CharField(max_length=30)
position = models.CharField(max_length=5)
Here is my main page view:
def main_page(request):
players = Player.objects.all()
my_dict = {"players":players}
return render(request, 'my_app/main_page.html', context=my_dict)
Here is my template for the main page:
{% extends "my_app/base.html" %}
{% block body_block %}
<button onclick="document.getElementById({{player.name}}).style.display='block'" class="w3-button w3-black">Open Modal</button>
<div class="w3-modal-content">
<div class="w3-container">
<span onclick="document.getElementById({{player.name}}).style.display='none'" class="w3-button w3-display-topright">×</span>
<p>{{player.position}}</p>
</div>
</div>
{% for player in players %}
<tr>
<th>{{player.name}}</th>
<th onclick="document.getElementById({{player.name}}).style.display='block'" class="w3-button w3-black" width="100%">Open Modal</th>
</tr>
{% endif %}
{% endblock %}
As you can see, I would like the modal popup to display the player's position.
Unfortunately, not only is the modal not working, I have no clue how to make it display attributes of my Player model.
Would anybody know how to modify my html to fix the modal?
Thank you very much for your help!
EDIT: found a very interesting answer on How do I integrate Ajax with Django applications?
I have the following templates in Flask (but I don't think that's a flask problem:
Contact.html
<button type="button" class="btn btn-secondary btn-sm" data-target="#score" data-toggle="collapse" data-placement="right">Score</button>
<div id="score" class="collapse">
<span class='dot green'></span> 1
</div>
Compare.html
<!-- I only added the key elements there are some other "formatting" parts.-->
{% include "contact.html" %}
{% include "contact.html" %}
As you see in Contact.html I use a collpase. Ref: https://www.w3schools.com/bootstrap/bootstrap_collapse.asp
My problem is that I compare two contacts and therefore they both have that div with id score.
If I now click on the first Button to reveal the score of the first contact then obviously both scores are revealed. But I only want to reveal the score of the contact I clicked.
My idea is instead of data-target="#score" to say something like: Take the next #score element but I don't know how I can do that.
I figure it out how to it. Basically it's easy in my case.
Because each contact has an unique id, I can use this to build the id like this:
<!-- Generate ID -->
{% set score_id = "score" + contact.idx|string %}
<!-- Use the ID in the collapse-->
<button type="button" class="btn btn-secondary btn-sm" data-target="#{{score_id}}" data-toggle="collapse" data-placement="right">Score</button>
<div id="{{score_id}}" class="collapse">
<span class='dot {{color}}'></span> {{ contact_score }}
</div>
Then only one will expanded if clicked on the Button. Therefore thanks #Anees Ijaz for the comment. The comment pushed me in the right direction.
How do I send a clicked link in html or selected information in the ComboBox to Django?
views.py
def musicList(request):
musics = Song.objects.filter()
print(musics)
con = sqlite3.connect(str(request.user)+".db")
cursor = con.cursor()
cursor.execute("Select name From sqlite_master Where type='table';")
tables = list()
for i in cursor.fetchall():
tables.append(i[0])
context = {
"musics":musics,
"tables":tables,
}
return render(request,"musicList.html",context)
musicList.html
{% for music in musics %}
<tr>
<th scope="row">{{music.id}}</th>
<td>{{music.artist}}</td>
<td>{{music.song_name}}</td>
<td>{{music.song_type}}</td>
<td>{{music.owner}}</td>
<td>
<div class="dropdown">
<button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown">
Choice a Music List
</button>
<div class="dropdown-menu">
{% for table in tables %}
<a class="dropdown-item" href="add_to_list/{{music.id}}" value="{{table}}">{{table}}</a>
{% endfor %}
</div>
</div>
</td>
</tr>
{% endfor %}
What do I do to return the value corresponding to the "value" of the link that the user clicked from the "dropdown-menu" to a different function in views.py
There are several methods to communicate from the template to the view.
1. Post method:
Make a form with inputs, check-boxes.. etc and their values, and retrieve the values in the view:
request.POST.get('value')
2. Via Url:
urls.py
urlpatterns = [
...
path('add_to_list/<int:music_id>/<str:value>', views.musicList, name='musicList'),
...
]
views.py
def detail(request, music_id, value):
...
More advanced explanation in the official documentation here.
You can also use
Query Parameters:
localhost:8000/?id=123
request.GET.get('id')
I'm in my final project and I'm a little bit lost on what I'm doing now.
I'm developping a website and I need to insert some choices into a html select tag, I mean, that choices must be options of this select tag. I'm trying it, but the dropdown doesn't appear as it should, and, when I try to submit my form, it gives me an error. I wish you could help me, I'm becoming crazy. Here I leave my code, feel free to ask anything you want
forms.py
class FormCancion(forms.ModelForm):
NOTAS_CHOICES=(('35','Acoustic Bass Drum'),('36','Bass Drum 1'),('37','Side Stick'),('38','Acoustic Snare'),('39','Hand Clap'),
('40','Electric Snare'),('41','Low Floor Tom'),('42','Closed Hi Hat'),('43','High Floor Tom'),('44','Pedal Hi-Hat'),
('45','Low Tom'),('46','Open Hi-Hat'),('47','Low-Mid Tom'),('48','Hi-Mid Tom'),('49','Crash Cymbal 1'),('50','High Tom'),
('51','Ride Cymbal 1'),('52','Chinese Cymbal'),('53','Ride Bell'),('54','Tambourine'),('55','Splash Cymbal'),
('56','Cowbell'),('57','Crash Cymbal 2'),('58','Vibraslap'),('59','Ride Cymbal 2'),('60','Hi Bongo'),('61','Low Bongo'),
('62','Mute Hi Conga'),('63','Open Hi Conga'),('64','Low Conga'),('65','High Timbale'),('66','Low Timbale'),('67','High Agogo'),
('68','Low Agogo'),('69','Cabasa'),('70','Maracas'),('71','Short Whistle'),('72','Long Whistle'),('73','Short Guiro'),
('74','Long Guiro'),('75','Claves'),('76','Hi Wood Block'),('77','Low Wood Block'),('78','Mute Cuica'),('79','Open Cuica'),
('80','Mute Triangle'),('81','Open Triangle'))
nota_pad_gris = forms.ChoiceField(choices=NOTAS_CHOICES, widget=forms.Select())
views.py:
def crearCancion(request):
cancion=Cancion()
if request.method=="POST":
formulario=FormCancion(request.POST,request.FILES,instance=cancion)
if formulario.is_valid():
formulario.save()
return HttpResponseRedirect('/ListadoCanciones/')
else:
formulario=FormCancion()
context={'formulario':formulario}
return render(request,"nuevaCancion.html",context)
.html:
<br><br><br>
<div class="container">
<form id='formulario' method='post' {% if formulario.is_multipart %} enctype="multipart/form-data" {% endif %} action=''>
{% csrf_token %}
<center>
<label for="nota_pad_gris">Nota del pad Gris:</label>
<select id="nota_pad_gris" onchange="validar();">
{% for value in formulario.nota_pad_gris %}
<option value="hola">{{ value }}</option>
{% endfor %}
</select>
<br><br>
<p><input type='submit' class="btn btn-success btn-lg" value='Añadir'/>
Cancelar</p>
</center>
</form>
<br>
</div>
Edit:
Look at Nota del pad gris. This is what the list shows. It shows the choices, but also shows a blank space between the choices.
[
This is the error that the web gives me when I try to submit the form
I was figuring how to reuse the same registration form and view on multiple templates and pages, and in different formats. E.g. on the page, in a modal etc. I am however some trouble in figuring out the best practice for solving this problem. One thing I am actively trying to avoid is repeating myself, but I can't seem to find a solution that is satisfying enough.
At the moment I have one central view that handles user registrations that looks like this. At the moment it can only handle to output one form on the signup_form template, but I want to extend that to the index page and be able to be outputted in a modal as well.
Views.py
def signup(request):
template_name = 'core/authentication/signup_form.html'
custom_error_list = []
if request.method == "POST":
form = SignUpForm(request.POST)
if form.is_valid():
#Check for duplciate email
email = form.cleaned_data.get('email')
username = form.cleaned_data.get('username')
if email and User.objects.filter(email=email).exclude(username=username).exists():
custom_error_list.append("A user with that email already exists")
else:
user = form.save(commit=False)
user.is_active = False
user.save()
current_site = get_current_site(request)
subject = 'Activate your StockPy Account'
sender = '' #Insert sender address here
message = render_to_string('core/authentication/account_activation_email.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)),
'token': account_activation_token.make_token(user)
})
user.email_user(subject, message)
return redirect('authentication:account_activation_sent')
else:
form = SignUpForm()
return render(request, template_name, {'form': form, 'custom_error_list': custom_error_list})
#Activate the user as he/she clicks the email verification link which lead to tihs view
def activate(request, uidb64, token):
try:
#Using a [:1] is ad-hoc solution to get rid of the starting 'b' symbol
uid = force_text(urlsafe_base64_decode(uidb64[1:]))
user = User.objects.get(pk=uid)
except (TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if user is not None and account_activation_token.check_token(user, token):
user.is_active = True
user.profile.email_confirmed = True
user.save()
login(request, user)
return redirect(template_name)
else:
return render(request, 'core/authentication/account_activation_invalid.html')
forms.py
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from django import forms
class LoginForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['email','password']
class SignUpForm(UserCreationForm):
email = forms.EmailField(max_length=254, widget=forms.TextInput(attrs={'placeholder': 'Email...', 'class' : 'form-control', 'pattern' : '[a-z0-9._%+-]+#[a-z0-9.-]+\.[a-z]{2,3}$'}))
class Meta:
model = User
fields = ['email', 'username', 'password1', 'password2']
def __init__(self, *args, **kwargs):
super(SignUpForm, self).__init__(*args, **kwargs)
self.fields['username'].widget = forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Username...',
})
self.fields['password1'].widget = forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Password...',
'type': 'password',
})
self.fields['password2'].widget = forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Password again...',
'type': 'password',
})
My signup form currently looks like this.
signup_form.html
{% extends 'base.html' %}
{% load static %}
<!-- End Navbar -->
{% block page-header %}
<div class="section section-signup" style="background-image: url({% static 'core/assets/img/bg8.jpg' %}); background-size: cover; background-position: top center; min-height: 700px;">
<div class="container">
<div class="row">
<div class="card card-signup" data-background-color="orange">
<form class="form" method="POST" action="">
{% csrf_token %}
<div class="header text-center">
<h4 class="title title-up">Sign Up</h4>
<div class="social-line">
<a href="#twitter" class="btn btn-neutral btn-twitter btn-icon btn btn-round">
<i class="fa fa-twitter"></i>
</a>
<a href="#facebook" class="btn btn-neutral btn-facebook btn-icon btn-lg btn-round">
<i class="fa fa-facebook-square"></i>
</a>
<a href="#google" class="btn btn-neutral btn-google btn-icon btn-round">
<i class="fa fa-google-plus"></i>
</a>
</div>
</div>
<div class="card-body">
<!-- Output error messages -->
{% for field in form %}
<div style="color:red; list-decorations:none;" class="text-center">
{{ field.errors.as_text }}
</div>
{% endfor %}
{% for error in custom_error_list %}
<div style="color:red;" class="text-center">
* {{ error }}
</div>
{% endfor %}
<!-- Output all fields -->
{% for field in form %}
<div class="input-group form-group-no-border">
<span class="input-group-addon">
<i class="now-ui-icons
{% if field.name == 'email' %} ui-1_email-85{% endif %}
{% if field.name == 'username' %} users_circle-08{% endif %}
{% if field.name == 'password1' %} ui-1_lock-circle-open{% endif %}
{% if field.name == 'password2' %} ui-1_lock-circle-open{% endif %}
"></i>
</span>
{{ field }}
<!-- Give input box red border if data is not valid -->
{% if field.errors %}
<script>
var element = document.getElementById("{{ field.id_for_label }}");
element.classList.add("form-control-danger");
</script>
{% endif %}
</div>
{% endfor %}
<div class="text-center">
Already registered? Log in here
</div>
<!-- If you want to add a checkbox to this form, uncomment this code -->
<!-- <div class="checkbox">
<input id="checkboxSignup" type="checkbox">
<label for="checkboxSignup">
Unchecked
</label>
</div> -->
</div>
<div class="footer text-center">
<button type="submit" class="btn btn-neutral btn-round btn-lg">Get Started</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock page-header %}
And a small example snippet of my index.html of how I want to implement it ish.
index.html
<div class="main">
<div class="section section-about-us">
<div class="container">
<div class="col-md-8 ml-auto mr-auto text-center">
{{ form }}
</div>
</div>
</div>
</div>
I have really tried to find a smooth way of doing this, but without result unfortunately.
It seems as though you already know how to implement the same form in multiple templates, but you've having trouble avoiding repetition in your code. To that end, here are some suggestions for reducing the amount of repetition you'll encounter when duplicating this form across multiple pages:
Validate data within your form rather than your view. Currently, you are checking for duplicate e-mail addresses within views.py. If you duplicated your form, you'd have to re-write that code all over again. Instead, why not move it into forms.py in a custom cleaning method (see Django docs on custom form cleaning).
Write functions for actions that will be repeated. For example, currently, you are sending an activation e-mail to your user within views.py. It makes more sense to write a function within your user/models.py called something like send_activation_email(). Whenever you want to send an activation e-mail to a user, you can then call user.send_activation_email() rather than duplicating your entire block of activation e-mail code (see Django docs on model methods).
Use inclusion tags to avoid repetition in your templates. If there's a block of code that you find yourself repeating in your templates, you can use Django's inclusion tags to include a snippet of HTML across multiple templates. This allows you to serve the same form in multiple locations without re-writing your code. If you want to style your form differently across multiple pages, you could wrap it in DIVs with different IDs and use CSS to style the form differently depending on which DIV it's wrapped in. (see Django docs on inclusion tags)