I know it might be a duplicate and or such a simple thing to ask here. Please assist if you know how to and ask for more details to help me sort my problem. DISCLAIMER: I am a django beginner.
I have a model which has a foreignkey field. I'd like to have the options passed into the foreignkey field display in checkboxes. I have not been able to get it work. These are what I have
class Students(models.Model):
school = models.ForeignKey(School, on_delete=models.CASCADE)
name = models.CharField(max_length=200,unique=True,help_text="Student's name")
form = models.ForeignKey(Form, on_delete=models.CASCADE)
class Form(models.Model):
school = models.ForeignKey(School, on_delete=models.CASCADE)
form = models.CharField(max_length=20)
All the options in form model are to be passed as check boxes in Students model
My forms.py is shown below
class StudentsForm(forms.ModelForm):
def __init__(self, school, *args, **kwargs):
super(StudentsForm, self).__init__(*args, **kwargs)
self.fields['form'] = forms.ModelChoiceField(
queryset=Form.objects.filter(school=school))
class Meta:
model = Students
fields = ("name",'form')
My views.py
class StudentView(LoginRequiredMixin,CreateView):
model = Students
form_class = StudentsForm
template_name = 'add_student.html'
success_url = reverse_lazy('students')
def get_form_kwargs(self):
kwargs = super(StudentView, self).get_form_kwargs()
kwargs['school'] = self.request.user.school
return kwargs
Could I have the options as checkboxes, please???
I would recommend using the default modelchoicefield for foreignkey relations which will give you a select box in your template. Javascript is not my best programming language but here's an answer on how to set this up:
models.py
from django.db import models
class School(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
class Students(models.Model):
school = models.ForeignKey(School, on_delete=models.CASCADE)
name = models.CharField(max_length=200, unique=True, help_text="Student's name")
def __str__(self):
return self.name
forms.py
from django import forms
from .models import Students
class StudentsForm(forms.ModelForm):
school = forms.CharField(widget=forms.HiddenInput)
class Meta:
model = Students
fields = ("name", "school")
views.py
from django.urls import reverse_lazy
from django.views.generic import FormView
from .forms import StudentsForm
from .models import Students, School
class StudentView(FormView):
template_name = 'add_student.html'
model = Students
form_class = StudentsForm
success_url = reverse_lazy('students')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['schools'] = School.objects.all()
return context
add_student.html
<form>
{{ form.as_p }}
<ul class="school__list">
{% for school in schools %}
<li class="school__list-item">{{ school.name }}
<input type="checkbox" class="school__list-item-checkbox"
value="{{ school.id }}" name="school"/>
</li>
{% endfor %}
</ul>
</form>
<script>
const schools = document.querySelectorAll('.school__list-item-checkbox');
for (let i = 0; i < schools.length; i++) {
schools[i].addEventListener('click', () => {
{# populate the hidden school field with the value that is checked here. #}
})
}
</script>
Related
I am trying to make a drop down select form (category) in django. The form renders well on the webpage but when I try to submit I get the error Select a valid choice. That choice is not one of the available choices.
I have done everything possible within my capability to resolve this. if you have any idea on how to go about this please help.
model.py
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('detail', args=[str(self.id)])
# return reverse('home')
class Post(models.Model):
title = models.CharField(max_length=100)
text = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
edited = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
category = models.CharField(max_length=100, default='coding')
def __str__(self):
return f'{self.title} by {self.author} {self.pk}'
def get_absolute_url(self):
return reverse('detail', args=[str(self.id)])
# return reverse('home')
form.py
from django import forms
from .models import Post, Category
choices = Category.objects.all().values_list('name','name')
choices_list = []
for item in choices:
choices_list.append(item)
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('title', 'category', 'author','text')
widgets={
'title': forms.TextInput(attrs={'class':'form-control'}),
'category': forms.Select(choices=choices_list, attrs={'class':'form-control'}),
'author': forms.TextInput(attrs={'class':'form-control', 'id':'author'}),
# 'author': forms.Select(attrs={'class':'form-control'}),
'text': forms.Textarea(attrs={'class':'form-control','placeholder':choices_list}),
}
class EditForm(forms.ModelForm):
class Meta:
model = Post
fields = ('title', 'text')
widgets={
'title': forms.TextInput(attrs={'class':'form-control'}),
'text': forms.Textarea(attrs={'class':'form-control','placeholder':"less than 500 words"}),
# 'author': forms.Select(attrs={'class':'form-control'})
}
views.py
class createarticleview(CreateView):
template_name='posts/addpost.html'
model = Post
form_class = PostForm
#fields = '__all__'
# fields = ('title','text') for certain fields
def get_context_data(self, *args, **kwargs):
cat_menu = Category.objects.all()
context = super(createarticleview, self).get_context_data(*args, **kwargs)
context['cat_menu'] = cat_menu
return context
addpost.html
{%extends 'index.html'%}
{%block content%}
{% if user.is_authenticated %}
<div class="container">
<h3>add post...!!!.{{user.username}}</h3>
<br>
<div class="mb-3">
<form method="POST"> {% csrf_token%}
{{form.as_p}}
<button type="submit" class="btn btn-info"> post</button>
</form>
</div>
</div>
<script>
var name = "{{user.username}}";
if(document.getElementById("author").value=name)
document.getElementById('author').readOnly = true;
</script>
{% else%}
<h3>you are not logged in</h3>
{%endif%}
{%endblock content%}
Firstly, Always use PascalCase while defining the name of class, like you can give CreateArticleView rather than createarticleview.
you haven't given choices while defining your model that is Post and given models.CharField().
Update your Post model with choices attribute.
Try this:
models.py
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
CATEOGRY_TYPES = (
('sp', 'sport'),
('te', 'technology'),
('bu', 'business')
)
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('detail', args=[str(self.id)])
# return reverse('home')
class Post(models.Model):
title = models.CharField(max_length=100)
text = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
edited = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
category = models.CharField(
choices=CATEOGRY_TYPES, max_length=2, default='coding')
def __str__(self):
return f'{self.title} by {self.author} {self.pk}'
def get_absolute_url(self):
return reverse('detail', args=[str(self.id)])
# return reverse('home')
views.py
from django.shortcuts import render
from .models import Post, Category
from .forms import PostForm
from django.views.generic.edit import CreateView
class CreateArticleView(CreateView):
template_name = 'posts/addpost.html'
model = Post
form_class = PostForm
success_url = '/success/'
def success(req):
return render(req, 'posts/success.html')
Rest of things will be remain same.
You can do it without reverse method by direclty making ForeignKey field in your Post model.
you can also do this:
models.py
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=100)
text = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
edited = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
category = models.ForeignKey(
Category, on_delete=models.CASCADE, default='coding')
def __str__(self):
return f'{self.title} by {self.author} {self.pk}'
views.py
from django.shortcuts import render
from .models import Post, Category
from .forms import PostForm
from django.views.generic.edit import CreateView
class CreateArticleView(CreateView):
template_name = 'posts/addpost.html'
model = Post
form_class = PostForm
success_url = '/success/'
def success(req):
return render(req, 'posts/success.html')
Your forms.py can be remain same.
Remember: choices while defining models will be given more preference than ForeignKey.
I am pretty new to Django and still learning it, but I have to create something like medium.com. I want to show posts to users according to their interests. I added an interests field with a checkbox in a sign-up form. And of course, I added a category to the Post model. So, how can I show (to logged-in users only) publications that they interested in?
Here is my models.py file in posts app
from django.db import models
from django.utils import timezone
from django.urls import reverse
# Create your models here.
class Post(models.Model):
CATEGORY = (
('sport', 'Sport'),
('science', 'Science'),
('it', 'IT'),
('art', "Art"),
)
title = models.CharField(verbose_name="Title for publication", max_length=50)
category = models.CharField(verbose_name="Category", choices=CATEGORY, max_length=50)
author = models.ForeignKey("accounts.User", verbose_name="Author:", on_delete=models.CASCADE)
body = models.TextField(verbose_name="Body for publication")
pub_date = models.DateTimeField(verbose_name="Date:", auto_now_add=True)
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
def get_absolute_url(self):
return reverse("post_detail", kwargs={"pk": self.pk})
def __str__(self):
return self.title
And here is my vies.py file in posts app
from django.views.generic import ListView, DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from .models import Post
from django.urls import reverse_lazy
class PostListView(ListView):
model = Post
template_name = "index.html"
def get_queryset(self):
return Post.objects.order_by('-pub_date')
class PostDetailView(DetailView):
model = Post
template_name = "./posts/post_detail.html"
class PostCreateView(CreateView):
model = Post
template_name = "./posts/new_post.html"
fields = '__all__'
class PostUpdateView(UpdateView):
model = Post
template_name = "./posts/update_post.html"
fields = ['body', 'title', 'category']
class PostDeleteView(DeleteView):
model = Post
template_name = "./posts/delete_post.html"
success_url = reverse_lazy('index')
class SportPostListView(ListView):
model = Post
template_name = "./posts/sports.html"
class ITPostListView(ListView):
model = Post
template_name = "./posts/it.html"
class SciencePostListView(ListView):
model = Post
template_name = "./posts/ilm-fan.html"
class ArtPostListView(ListView):
model = Post
template_name = "./posts/sanat.html"
Here is my index.html file
{% extends 'base.html' %}
{% block content %}
{% if object_list %}
{% for post in object_list %}
<h1>{{ post.title }}</h1>
<p>{{ post.pub_date }}</p>
<p>{{ post.author }}</p>
<p>{{ post.body }}</p>
<p>{{ post.category }}</p>
{% endfor %}
{% else %}
<p>No posts are available.</p>
{% endif %}
{% endblock content %}
This is my forms.py file in accounts app
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django.db import models
from django import forms
class SignUpForm(UserCreationForm):
INTERESTS = (
('sport', 'Sport'),
('science', 'Science'),
('it', 'IT'),
('art', "Art"),
)
username = forms.CharField(max_length=128, required=True)
email = models.EmailField(verbose_name='emailingiz', unique=True, default='')
first_name = forms.CharField(max_length=128, required=True)
last_name = forms.CharField(max_length=128, required=True)
interests = forms.MultipleChoiceField(required=True, widget=forms.CheckboxSelectMultiple, choices=INTERESTS)
USERNAME_FIELD = 'email'
class Meta:
model = User
fields = ('first_name', 'last_name', 'username', 'email', 'interests', 'password1', 'password2')
And lastly this views.py file in accounts app
from django.urls import reverse_lazy
from django.views.generic import CreateView
from .forms import SignUpForm
class SignUpView(CreateView):
form_class = SignUpForm
success_url = reverse_lazy('login')
template_name = 'signup.html'
I have no idea how to do this, but I know that I have to do something in the views.py file in the posts app, however, I do not know what to do.
Will be really grateful if you could help me.
I would make another model Category. Since it will be its own model, you will be able to add future categories on the fly if needed, rather than having those hardcoded choices.
class Category(models.Model):
name = models.CharField(default=None, blank=True, null=True)
Then your User and Post model will each have a ManytoMany field related to category. Posts can be tagged as certain categories when they are created, and Users will be able to select a number of categories that they are interested in and have them stored in this field:
class User(AbstractBaseUser):
interests = models.ManytoManyField(Category, default=None, blank=True)
class Post(models.Model):
categories = models.ManytoManyField(Category, default=None, blank=True)
You can make use of a forms.modelChoiceField which will enable your user to select a category.
In your PostListView, all you need to do is change the get_queryset method to filter for posts that the user likes.
class PostListView(ListView):
model = Post
template_name = "index.html"
def get_queryset(self):
user_interests = self.request.user.interests
return Post.objects.filter(
categories__in=user_interests).order_by('pub_date')
Then, you should get the posts that share categories with the user's interests.
Here is the error
Error during template rendering
In template /home/xesos/projects/mw/mw/templates/base.html, error at line 0
too many values to unpack (expected 2)
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <style>
7
8 </style>
9 <title>
10 {% block title %}
To avoid this error I did some changes in forms.py, here is it
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django import forms
from posts.models import Category
class SignUpForm(UserCreationForm):
categories = Category.objects.values_list('name')
listOfCategory = []
listOfCategory += categories
username = forms.CharField(max_length=128, required=True)
email = forms.EmailField(required=True)
first_name = forms.CharField(max_length=128, required=True)
last_name = forms.CharField(max_length=128, required=True)
USERNAME_FIELD = 'email'
for i in range(0, len(listOfCategory)):
listOfCategory.append(listOfCategory[i])
interests = forms.ChoiceField(choices=[(x, x) for x in listOfCategory])
class Meta:
model = User
fields = ('first_name', 'last_name', 'username', 'email', 'interests', 'password1', 'password2')
I am trying to display the data in details template that I would obtain using AgentForm and I am also trying to add a Matrix1Form that will be unique to each agent, and that matrix1form would be displayed in details.html.
Here is my views.py and if I try to display the Matrix1Form, the data from Agent model doesn't get displayed and vice versa, if I want to display an agent, I have to comment out the Matrix1Form. There are no errors popping up so far. The data just don't get displayed.
views.py
class AgentDetailsView(generic.DetailView):
template_name = 'User/AgentDetails.html'
class Meta:
model = Agent
def get(self, request, *args, **kwargs):
matrix1form = Matrix1Form()
return render(request, self.template_name, {'matrix1form':
matrix1form})
forms.py
class AgentForm(forms.ModelForm):
prefix = 'agentform'
class Meta:
model = Agent
fields = '__all__'
class Matrix1Form(forms.ModelForm):
prefix = 'matrix1form'
class Meta:
model = Matrix1
fields = '__all__'
models.py
class Agent(models.Model):
AgencyName = models.CharField(blank=True, max_length = 50,
verbose_name="Agency Name")
OtherAgencyName = models.CharField(max_length=50, blank=True)
FirstName = models.CharField(max_length=50, null=True)
LastName = models.CharField(max_length=50, null=True)
details.html
<ul>
<li>AgencyName: {{agent.AgencyName}} </li>
<li>OtherAgencyName: {{agent.OtherAgencyName}} </li>
<li>First Name: {{agent.FirstName}} </li>
<li>Last Name: {{agent.LastName}} </li>
</ul>
<form class="form-horizontal" action="" method="post"
enctype="multipart/form-data">
{% csrf_token %}
<table>
{{ matrix1form.as_table }}
</table>
</form>
if i understand you correct, you need to override get_context_data for example:
class AgentDetailsView(generic.DetailView):
template_name = 'User/AgentDetails.html'
class Meta:
model = Agent
def get_context_data(self, **kwargs):
# ^^^^^^^^^^^^^^
context = super(AgentDetailsView, self).get_context_data(**kwargs)
matrix1form = Matrix1Form()
context['matrix1form'] = matrix1form
return context
I am working with forms (forms.ModelForm) and I have some small inconvenient when I create my form based in the models. My situation such as follow in my models.py file:
I have the CorporalSegment model:
class CorporalSegment(models.Model):
SEGMENTO_HOMBRO = 'Hombro'
SEGMENTO_CODO = 'Codo'
SEGMENTO_ANTEBRAZO = 'Antebrazo'
SEGMENTO_MANO = 'Mano'
SEGMENT_CHOICES = (
(SEGMENTO_HOMBRO, u'Hombro'),
(SEGMENTO_CODO, u'Codo'),
(SEGMENTO_ANTEBRAZO, u'Antebrazo'),
(SEGMENTO_MANO, u'Mano'),
)
corporal_segment = models.CharField(
max_length=12,
choices=SEGMENT_CHOICES,
blank=False,
)
class Meta:
verbose_name_plural = 'Segmentos Corporales'
def __str__(self):
return "%s" % self.corporal_segment
I have the Movement model
class Movements(models.Model):
name = models.CharField(
max_length=255,
verbose_name='Movimiento'
)
class Meta:
verbose_name_plural = 'Movimientos'
def __str__(self):
return "%s" % self.name
And I have the Metric model
class Metrics(models.Model):
name = models.CharField(
max_length=255,
blank=True,
verbose_name='Nombre'
)
value = models.DecimalField(
max_digits = 5,
decimal_places = 3,
verbose_name = 'Valor',
null = True,
blank = True
)
class Meta:
verbose_name = 'Métrica'
def __str__(self):
return "{},{}".format(self.name, self.value)
My purpose is that in one form, I can save multiple values (instances) of CorporalSegment, Movement and Metric models, and due to this, I have the PatientMonitoring model of this way:
class PatientMonitoring(models.Model):
patient = models.ForeignKey(...)
medical = models.ForeignKey(...)
# My fields pointing to my previous models with many to many relationship
corporal_segment = models.ManyToManyField(CorporalSegment, verbose_name='Segmentos Corporales')
movement = models.ManyToManyField(Movements, verbose_name='Movimientos')
metrics = models.ManyToManyField(Metrics, verbose_name='Métricas', )
class Meta:
verbose_name = 'Monitoreo del paciente'
def __str__(self):
return "%s" % self.patient
My views.py file
class PatientMonitoringCreate(CreateView):
model = PatientMonitoring
form_class = PatientMonitoringForm
success_url = reverse_lazy('patientmonitoring:list')
class PatientMonitoringUpdate(UpdateView):
model = PatientMonitoring
form_class = PatientMonitoringForm
success_url = reverse_lazy('patientmonitoring:list')
My forms.py is of this way:
from django import forms
from .models import PatientMonitoring
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
class PatientMonitoringForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(PatientMonitoringForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.add_input(Submit('submit', u'Save'))
# I think so that here is my problem ...
def save(self, commit=True):
patient_monitoring = super(PatientMonitoringForm, self).save(commit=False)
patient = self.cleaned_data['patient']
if commit:
patient_monitoring.save()
return patient_monitoring
class Meta:
model = PatientMonitoring
fields = ['patient', 'medical','corporal_segment','movement','metrics']
And my template patientmonitoring_form.html is:
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}Crear Registro de Monitoreo de Paciente{% endblock %}
{% block content %}
<div>
{% crispy form %}
{% csrf_token %}
</div>
{% endblock %}
When I want save a PatientMonitoring instance in their respective form, the corporal_segment (Segmentos Corporales) movement (Movimientos) and metrics (Metricas) fields in the form, their values are not saved in the form (in squares red), but the another fields are saved (not red squared)
This behavior is strange for me, because via Django admin form, is possible save a PatientMonitoring instance with all their attributes.
What thing can I will be ignoring in the moment of save in my form save method in my PatientMonitoringForm in forms.py file?
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#the-save-method
When using commit=False, you have to call save_m2m()
m2m relationships require the parent object to be saved first, which you are not doing by using commit=False.
UPDATE
I was able to accomplish this in my Project models.py, but I feel this belongs in my view. How would I go about doing this? Code:
#property
def related_project_set(self):
category_id_list = self.category.values_list("id", flat=True)
return Project.live.filter(category__id__in=category_id_list).exclude(id=self.id)[:5]
I'd like to display "projects" related by "category" in my generic class-based detail view for project. I'm also using the Django-Braces PrefetchRelated Mixin. But I don't understand why the Python interpreter displays different results than my template.
For example, given two projects in the db, I get the following result:
>>> from projects.models import Project
>>> Project.objects.all().prefetch_related('category')
[<Project: Avalon Road>, <Project: Piedmont Avenue>]
Models:
class Project(models.Model):
"""
A project completed by ICON.
"""
LIVE_STATUS = 1
DRAFT_STATUS = 2
STATUS_CHOICES = (
(LIVE_STATUS, 'Live'),
(DRAFT_STATUS, 'Draft'),
)
title = models.CharField(max_length=200)
slug = models.SlugField(help_text='Populates from title field.')
date_completed = models.DateField(null=True, blank=True)
vison_description = models.TextField(help_text='Please use Markdown syntax. No HTML is allowed.')
work_description = models.TextField(help_text='Please use Markdown syntax. No HTML is allowed.')
category = models.ManyToManyField(Category)
lead_photo = models.ImageField(upload_to='projects/photos', help_text='Will also be used as thumbnail for category listing.')
gallery = models.ForeignKey(Gallery)
status = models.IntegerField(choices=STATUS_CHOICES, default=2, help_text="Only projects with a status of 'live' will be displayed publicly.")
objects = models.Manager()
live = LiveProjectManager()
class Category(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(help_text='Populates from title field.')
description = models.TextField(help_text='Please use Markdown syntax. No HTML is allowed.', blank=True)
class Meta:
verbose_name_plural = 'Categories'
ordering = ('title',)
def __str__(self):
return self.slug
#models.permalink
def get_absolute_url(self):
return ('categories:detail',
(),
{'slug': self.slug})
Views:
from __future__ import absolute_import
from braces.views import PrefetchRelatedMixin
from django.shortcuts import render
from django.views.generic import DetailView, ListView
from .models import Project
from categories.models import Category
from testimonials.models import Testimonial
class ProjectDetailView(PrefetchRelatedMixin, DetailView):
prefetch_related = ['category']
queryset = Project.live.all()
def get_context_data(self, **kwargs):
"""
Allow the project detail view to display a list of testimonials.
"""
context = super(ProjectDetailView, self).get_context_data(**kwargs)
context['testimonial_list'] = Testimonial.displayed.all()
return context
class ProjectListView(ListView):
queryset = Project.live.all()
def get_context_data(self, **kwargs):
"""
Allow the project list view to display a list of categories.
"""
context = super(ProjectListView, self).get_context_data(**kwargs)
context['category_list'] = Category.objects.all()
return context
Template snippet:
<ul>
{% for project in object.category.all %}
<li>{{ project.title }}</li>
{% endfor %}
</ul>