How to pass conditional attributes to template in Django ListView - django

I'm trying to make a list of employees that each day contains information ("today_note") if they are present at work or are sick.
I had no problem to do this in Flask, I simply rendered a template as below:
def employees_list():
all_employees = Employee.query.order_by(Employee.name).all()
today = date.today()
for employee in all_employees:
today_sick = db.session.query(SickLeave).filter(SickLeave.start_date <= today).filter(
SickLeave.end_date >= today).filter(SickLeave.person_id == employee.id).all()
if len(today_sick) != 0:
employee.today_note = "C"
else:
employee.today_note = "✓"
return render_template("employees_list.html", all_employees=all_employees)
and could access today_note for each employee in the template:
{% for employee in all_employees %}
{{ employee.today_note }}
{% endfor %}
Now I need to do the same in django. I can't figure out how to pass today_note to each instance of User model to be able to display it in the template.
class AllEmployeesList(ListView):
template_name = "users/all_employees.html"
model = User
context_object_name = 'employees'
def get_context_data(self, **kwargs):
context = super(AllEmployeesList, self).get_context_data(**kwargs)
all_employees = User.objects.all()
today = date.today()
for employee in all_employees:
today_sick = Sickleave.objects.filter(Q(start_date__lte=today)&Q(end_date__gte= today)&Q(employee__id=employee.id)).all()
if len(today_sick) != 0:
employee.today_note = "C"
else:
employee.today_note = "✓"
return context
I'm aware that here I completely miss reference to context
Edit: here are models
class Sickleave(models.Model):
TYPE_CHOICES = (
('C', 'Sickleave'),
('O', 'Other'),
)
employee = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE, related_name='sickemployee', default=""
)
type_name = models.CharField(max_length=10, choices=TYPE_CHOICES, default='C')
start_date = models.DateField(null=True)
end_date = models.DateField(null=True)
class User(AbstractBaseUser):
username = models.CharField('Username', max_length=15, unique=True)
email = models.EmailField('Email', null=True, blank=True)
first_name = models.CharField('First name', max_length=30)
last_name = models.CharField('Last name', max_length=50)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
# (...)
USERNAME_FIELD = 'username'
objects = UserManager()
def has_perm(self, perm, obj=None):
return self.is_superuser
def has_module_perms(self, app_label):
return self.is_superuser
def get_full_name(self):
return self.first_name+" "+self.last_name
def __str__(self):
return self.first_name + " "+ self.last_name

Related

Trying to embed a form within a form of foreign keys

I'm trying to create a form where a logged in user (PrincipalGuest) can update themselves but also multiple guests (AccompanyingGuest). I want an entire form with the attending and dietary_restrictions field embedded within a form, not just the ModelMultipleChoiceField.
models.py
class Guest(models.Model):
""" """
attending = models.ManyToManyField("itinerary.Event", blank=True)
dietary_restrictions = models.ManyToManyField(DietaryRestrictions, blank=True)
last_modified = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class PrincipalGuest(Guest, AbstractUser):
""" """
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
username = None
email = models.EmailField(_("email address"), unique=True)
phone_number = PhoneNumberField(null=True)
address = AddressField(on_delete=models.CASCADE, null=True)
objects = PrincipalGuestManager()
#property
def name(self):
return self.first_name + " " + self.last_name
def __str__(self):
return self.name
class AccompanyingGuest(Guest):
""" """
principal = models.ForeignKey(
PrincipalGuest, related_name="accompanying_guests", on_delete=models.CASCADE
)
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
is_under_ten = models.BooleanField(default=False)
#property
def name(self):
return self.first_name + " " + self.last_name
def __str__(self):
return self.name
views.py
class RendezvousFormView(SuccessMessageMixin, UpdateView):
template_name = "rsvp.html"
form_class = RendezvousForm
success_url = "/rsvp"
success_message = "Thank you for your RSVP"
def get_object(self):
return self.request.user
forms.py
class RendezvousForm(ModelForm):
""" """
first_name = CharField(
label="", widget=TextInput(attrs={"placeholder": "First Name"})
)
last_name = CharField(
label="", widget=TextInput(attrs={"placeholder": "Last Name"})
)
email = CharField(label="", widget=TextInput(attrs={"placeholder": "Email"}))
phone_number = CharField(
label="", widget=TextInput(attrs={"placeholder": "Phone Number"})
)
address = AddressField(
label="", widget=AddressWidget(attrs={"placeholder": "Home Address"})
)
attending = ModelMultipleChoiceField(
queryset=Event.objects.all(),
required=False,
label="Will be attending",
widget=CheckboxSelectMultiple(attrs={"class": "h4"}),
)
dietary_restrictions = ModelMultipleChoiceField(
DietaryRestrictions.objects.all(),
required=False,
widget=CheckboxSelectMultiple(attrs={"class": "h4"}),
)
class Meta:
model = PrincipalGuest
fields = [
"first_name",
"last_name",
"email",
"phone_number",
"address",
"attending",
"dietary_restrictions",
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.label_suffix = ""
self.fields["accompanying_guests"] = ModelMultipleChoiceField(
queryset=AccompanyingGuest.objects.filter(principal=kwargs["instance"])
)

error datefiled input when add new record

I have next problem.
I have models: Period and CompletedWork
class Period(models.Model):
date = models.DateField()
def __repr__(self):
return self.date
class CompletedWork(models.Model):
period = models.ForeignKey(directory.Period,
on_delete=models.SET('deleted date'),
)
worker = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET('deleted worker'),
related_name='worker_do', default=settings.AUTH_USER_MODEL
)
work_done = models.ForeignKey(directory.WorksType, on_delete=models.SET('deleted works type'))
work_scope = models.FloatField(blank=True, null=True)
work_notes = models.CharField(_("Comments"), max_length=70, blank=True, null=True, )
record_author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET('deleted user'),
related_name='record_author', auto_created=True,
)
record_date = models.DateTimeField(auto_now=True)
checked_by_head = models.BooleanField(default=False)
active = models.BooleanField(default=True)
def __repr__(self):
return f'{self.period}, {self.worker}, {self.work_done}'
def __str__(self):
return self.__repr__()
def is_active(self):
if self.active:
return True
return False
def __str__(self):
return str(self.__repr__())
In the forms I make a widget for Date input:
class CompletedWorkForm(forms.ModelForm):
class Meta:
model = CompletedWork
fields = (
'period',
'worker',
'work_done',
'work_scope',
'work_notes',
)
widgets = {
'period': DatePickerInput(),
}
widget.py looks like this:
class DatePickerInput(forms.DateInput):
input_type = 'date'
my view:
class CreateCompletedWorkView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = CompletedWork
form_class = CompletedWorkForm
template_name = 'completed_work_add.html'
success_url = reverse_lazy('completed_work_list')
success_message = f'Record successfully added'
def get_form_kwargs(self):
kwargs = super(CreateCompletedWorkView, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
def form_valid(self, form):
form.instance.record_author = self.request.user
return super().form_valid(form)
And now I have a problem creating a new record:
"Select a valid choice. That choice is not one of the available choices."
Please tell me how can I fixed. I understand, that maybe problem with the format that I get after POST

How to associate foreignkey data in django 3.0

How do I pull all of the users and put their full name into a context that I pass to a view? My view currently pulls all of the filtered rows and I want to replace the id of the user with their full name before I pass the context to the view. This is probably very simple, but I can't seem to make it work. The field trigger_caused_by holds the id of the user that made the change that fired the trigger.
Account models.py
class User(AbstractBaseUser):
email = models.EmailField(max_length=255, unique=True, verbose_name="Email Account")
first_name = models.CharField(max_length=50, blank=True, null=True, verbose_name="First Name")
last_name = models.CharField(max_length=50, blank=True, null=True, verbose_name="Last Name")
active = models.BooleanField(default=False, verbose_name="Is Account Active")
approved = models.BooleanField(default=False, verbose_name="Is Account Approved")
readonly = models.BooleanField(default=True, verbose_name="Read Only Account")
staff = models.BooleanField(default=False, verbose_name="Staff Account")
admin = models.BooleanField(default=False, verbose_name="Admin Account")
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = UserManager()
def __str__(self):
return f"{self.email} - {self.last_name}, {self.first_name}"
def get_full_name(self):
if self.last_name and self.first_name:
full_name = self.last_name + ", " + self.first_name
return full_name
return self.email
def get_short_name(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.staff
#property
def is_admin(self):
return self.admin
#property
def is_active(self):
return self.active
#property
def is_approved(self):
return self.approved
#property
def is_readonly(self):
return self.readonly
#property
def user_id(self):
return self.id
Historical models.py
class TCVBaseHistorical(models.Model):
opportunity_id = models.CharField(max_length=5, blank=True, verbose_name='Connected Oppporunity ID')
trigger_type = models.CharField(max_length=20, blank=True, verbose_name='Trigger Type')
new_trigger_value = models.CharField(max_length=40, blank=True, null=True, verbose_name='New Trigger Value')
datetime_of_trigger = models.DateTimeField(auto_now=False, blank=True, null=True,
verbose_name='Date/Time of Trigger')
new_date_value = models.DateField(auto_now=False, blank=True, null=True, verbose_name='New Date Value')
date_field_changed = models.CharField(max_length=10, blank=True, null=True, verbose_name="Date Field Changed")
money_field_changed = models.CharField(max_length=10, blank=True, null=True, verbose_name="Money Field Changed")
estimated = models.DecimalField(max_digits=12, decimal_places=2, blank=True, default=0.0,
verbose_name='Estimated')
estimated_base = models.DecimalField(max_digits=12, decimal_places=2, blank=True, default=0.0,
verbose_name='Estimated Base')
trigger_caused_by = models.CharField(max_length=5, blank=True, null=True, verbose_name='Trigger Caused By')
active = models.BooleanField(blank=True, null=True, default=True)
# def __str__(self):
# if self.trigger_type == 'tier':
# return f'{self.trigger_type} - '{self.opportunity_id} - {self.trigger_caused_by} - {self.active}'
class Meta:
verbose_name = 'Historical'
verbose_name_plural = 'Historicals'
#property
def is_active(self):
return self.active
Historical views.py
class HistoricalRoleList(ListView):
model = TCVBaseHistorical
paginate_by = 10
template_name = "Opportunity/Historical/HistRole.html"
def get_context_data(self, **kwargs):
list_historicals = super(HistoricalRoleList, self).get_context_data(**kwargs)
usersinfo = User.objects.all()
for _ in list_historicals:
caused_by = getattr(list_historicals, 'trigger_caused_by')
for _ in usersinfo:
user = getattr(usersinfo, str(User.user_id))
if caused_by == user:
list_historicals.full_name = user.get_full_name()
return list_historicals
def get_queryset(self):
qs = super().get_queryset()
cur_opp = Current_Opportunity.objects.get().current_opportunity
return qs.filter(trigger_type='role', opportunity_id=cur_opp).order_by('-datetime_of_trigger')

Saving formset when a compulsory field was not supplied?

I get an error "NOT NULL constraint failed" when I try to save a formset in an update view and the formset has had new forms added. I think the reason is that the database has a required field (journal_entry) that isn't part of the Formset ModelForm. So when the formset is attempted to be saved lineitem_formset.save() I get the error.
How can I add this required field value before saving the formset?
View.py
#login_required
def entries_update(request, pk):
journal_entry = get_object_or_404(JournalEntry, pk=pk)
journal_entry.date = journal_entry.date.strftime('%Y-%m-%d') #Convert date format to be suitable for Datepicker input.
journal_entry_form = JournalEntryForm(instance=journal_entry)
LineItemFormSet = modelformset_factory(LineItem, fields=('ledger','description','project','cr','dr'), extra=2)
line_items = LineItem.objects.filter(journal_entry=journal_entry)
lineitem_formset = LineItemFormSet(queryset=line_items)
if request.method == 'POST':
lineitem_formset = LineItemFormSet(request.POST)
journal_entry_form = JournalEntryForm(request.POST, instance=journal_entry)
if lineitem_formset.is_valid() and journal_entry_form.is_valid:
lineitem_formset.save() <-- ERROR HAPPENS HERE
journal_entry_form.save()
messages.success(request, "Journal entry successfully updated.")
return HttpResponseRedirect(reverse('journal:entries_show_detail', kwargs={'pk': journal_entry.id}) )
Models.py
class JournalEntry(models.Model):
# User needs to be set back to compulsory !!!
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=True, blank=True)
date = models.DateField(null=False, blank=False)
TYPE = (
('BP', 'Bank Payment'),
('YE', 'Year End'),
('JE', 'Journal Entry')
)
type = models.CharField(
max_length=2,
choices=TYPE,
blank=True,
default='0'
)
description = models.CharField(max_length=255, null=True, blank=True)
def __str__(self):
if self.description:
return self.description
else:
return 'Journal Entry' + str(self.id)
class Meta(object):
ordering = ['id']
verbose_name_plural = 'Journal entries'
class LineItem(models.Model):
journal_entry = models.ForeignKey(JournalEntry, on_delete=models.CASCADE) <--- This is the field that needs to be set.
ledger = models.ForeignKey(Ledger, on_delete=models.PROTECT)
description = models.CharField(max_length=255, null=True, blank=True)
project = models.ForeignKey(Project, on_delete=models.SET_NULL, null=True, blank=True)
cr = models.DecimalField(max_digits=8, decimal_places=2, null=True, blank=True)
dr = models.DecimalField(max_digits=8, decimal_places=2, null=True, blank=True)
STATUS = (
('0', 'Not reconciled'),
('1', 'Draft'),
)
status = models.CharField(
max_length=1,
choices=STATUS,
default='0'
)
reconciliation_date = models.DateField(null=True, blank=True)
#def __str__(self):
# return self.description
class Meta(object):
ordering = ['id']
forms.py
class JournalEntryForm(ModelForm):
def clean_date(self):
data = self.cleaned_data['date']
#Check date is not more than 30d future
if data > (datetime.date.today() + datetime.timedelta(30)):
raise ValidationError('Date cannot be more than 30d future')
if data < (datetime.date.today() - datetime.timedelta(90)):
raise ValidationError('Date cannot be more than 90d past')
return data
class Meta:
model = JournalEntry
fields = ['date','description']
widgets = {'date': DateTypeInput()}
class LineItemForm(ModelForm):
class Meta:
model = LineItem
fields = ['ledger','description','project','cr','dr']
# This init disallows empty formsets
def __init__(self, *arg, **kwarg):
super(LineItemForm, self).__init__(*arg, **kwarg)
self.empty_permitted = False
def clean(self):
cr = self.cleaned_data['cr']
dr = self.cleaned_data['dr']
if cr == None and dr == None:
raise ValidationError('You must enter a CR or DR.')
if cr and dr:
raise ValidationError('You must enter a CR or DR, not both.')
Thanks to #Iain Shelvington again. Edited the following lines to use inline_formset and now works:
LineItemFormSet = inlineformset_factory(JournalEntry, LineItem, fields=('ledger','description','project','cr','dr'), extra=2)
and:
lineitem_formset = LineItemFormSet(request.POST, instance=journal_entry)

How to group list items by user

I have an object with foreign key Edp. A user can have several RespostaEdp as per the design. However, when printing the list I want to group them by user. Any ideas on how to get this done? I tried the solution below but I cannot access user values.
#teacher_required
def listarRespostasEDA(request):
edpsTodas = Edp.objects.all()
title = 'Estruturas Digitais Pedagogicas'
template = 'edp/listarEDArespondida.html'
edps = list()
for edp in edpsTodas:
if edp.respostas.all().count() != 0:
# if not edp.respostas.none:
edps.append(edp)
return render(request, template, {'title': title, 'edps': edps})
def listaAlunosResponderamEdp(request, slug):
edp = get_object_or_404(Edp, slug=slug)
# respostas = RespostaEdp.objects.filter(edp=edp)
lista = list()
respostas = RespostaEdp.objects.filter(edp=edp).values('aprendiz').distinct().order_by('aprendiz')
for r in respostas:
for k,v in r.items():
aluno = User.objects.filter(pk=v)
lista.append(aluno)
print (lista)
return render(request, 'edp/teste.html', {'lista':lista})
class RespostaEdp(models.Model):
edp = models.ForeignKey(Edp, verbose_name='Edp', related_name='respostas', on_delete=models.CASCADE)
video_embedded = EmbedVideoField(blank=True, null=True)
texto = models.TextField('Texto', blank=True)
video = models.FileField(upload_to='video/', storage=upload_storage, default="media/none.mp4")
aprendiz = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='aluno', related_name='respostaAluno', on_delete=models.CASCADE)
# aprendiz = models.ForeignKey(Student, verbose_name='aprendiz ', related_name='respostaAprendiz', on_delete=models.CASCADE)
created_at = models.DateTimeField('Criado em', auto_now_add=True)
updated_at = models.DateTimeField('Atualizado em', auto_now=True)
def __str__(self):
return self.edp.titulo + " - " + self.aprendiz.username
def iniciar(self):
self.save()
#models.permalink
def get_absolute_url(self):
return ('edp:detalhe_edp_resposta', (), {'slug': self.slug})
class Meta:
verbose_name = 'Resposta Estrutura Digital de Aprendizagem'
verbose_name_plural = 'Resposta Estrutura Digital de Aprendizagem'
ordering = ['-created_at']
class User(AbstractUser):
eh_aluno = models.BooleanField(default=False)
eh_professor = models.BooleanField(default=False)
And here is the models of the users:
class User(AbstractUser):
eh_aluno = models.BooleanField(default=False)
eh_professor = models.BooleanField(default=False)
class Student(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
def __str__(self):
return self.user.username