Django empty list when using ModelChoiceField - django

First of all, I'm new to Django or MVC frameworks in general and I've got quite little experience in Python.
I've read stackoverflow threads with similar title, but yet I'm missing some puzzle piece.
After trying for some time, this is what I ended up with... which renders empty list. I think it's due to the fact, that the referred table has no database entries. I can't seem to figure out how to evaluate values based on FK from another table:
models.py
class Employees(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
def __str__(self):
return self.last_name
def get_absolute_url(self):
return reverse('employees')
class Tasks(models.Model):
type = models.CharField(max_length=30)
duration = models.IntegerField()
def __str__(self):
return self.type
def get_absolute_url(self):
return reverse('tasks')
class Records(models.Model):
employee_id = models.ForeignKey(Employees)
task_id = models.ForeignKey(Tasks)
date_from = models.DateTimeField()
date_to = models.DateTimeField()
def __str__(self):
return self.id
def get_absolute_url(self):
return reverse('records')
forms.py
class CreateRecordForm(forms.ModelForm):
employee_id = forms.ModelChoiceField(queryset=Records.objects.all().values('employee_id'))
task_id = forms.ModelChoiceField(queryset=Records.objects.all().values('task_id'))
date_from = forms.DateTimeField() #doesnt matter at the moment
class Meta:
model = Records
fields = ('employee_id', 'task_id', 'date_from')
views.py
class RecordCreateView(CreateView):
form_class = CreateRecordForm
template_name = 'record_new.html'
model = Records
#fields = ['employee_id', 'task_id', 'date_from']
Generic view below renders the drop-down selection correctly, so it is doable.
class RecordCreateView(CreateView):
template_name = 'record_new.html'
model = Records
fields = ['employee_id', 'task_id', 'date_from']
record_new.html
{% extends 'base.html' %}
{% block content %}
<h1>New record</h1>
<form action="" method="post">{% csrf_token %}
{{ form }}
<button class="btn btn-success ml-2" type="submit">save</button>
</form>
{% endblock content %}
Any help is greatly appreciated!

Related

Django 3.0 update a model inside of a detailview

I have a "project" model that has a "status" field. The status can be active, paused, or complete. I want to be able to update the field via form on the project detail view.
I have read a few solutions to this problem but, as a newbie, I haven't been able to get this to work. When I submit the form I get an http 405 error and the instance is not updated.
the model:
class Project(models.Model):
title = models.CharField(max_length= 200)
description = tinymce_models.HTMLField()
status = models.CharField(max_length=20, choices=PROJECT_CHOICES, default="active")
date = models.DateTimeField(auto_now_add=True, null=True)
created_by = models.ForeignKey(CustomUser, editable=False, null=True, blank=True, on_delete=models.RESTRICT)
objects = ProjectManager()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('company_project:project_detail', args=[str(self.id)])
the view
class CompanyProjectsDetailView(DetailBreadcrumbMixin, FormMixin, DetailView):
model = Project
id = Project.objects.only('id')
template_name = 'company_accounts/project_detail.html'
context_object_name = 'project'
form_class = ProjectStatusForm
notescount = Project.objects.annotate(num_notes=Count('notes'))
documentscount = Project.objects.annotate(num_documents=Count('project_documents'))
todoscount = Project.objects.annotate(num_documents=Count('todo_group'))
def form_valid(self, form):
project = get_object_or_404(Project, id=self.kwargs.get('pk'))
theform = form.save(commit=False)
theform.project = project
form.save()
return super(CompanyProjectsDetailView, self).form_valid(form)
the form
class ProjectStatusForm(forms.ModelForm):
class Meta:
model = Project
fields = ['status']
labels = {'status': 'project status'}
widgets = {
'status': forms.Select(attrs={'id':'PROJECT_CHOICES'}),
}
On the page I use this code to add the form
<form action="" method="post">
{% csrf_token %}
{{ form.media }}
{{ form|crispy }}
</br>
<input type="submit" value="save">
</form>

How can I get the ids of a queryset from a model and store them into a different model using a form?

I have a model called 'Competicion', with some objects and another model called 'Participante'. This second model has two fields: a foreignkey with the user and another foreingkey to 'Competicion'.
In the view, I've made queryset from 'Competicion' and with a for loop in the template I've given each object the button of the form.
With storing the user of the current session I have no problem but I want the form to know which object of the queryset it is to grab its id. #I have no problem with choices I just don't include them to save space
Models.py
class Competicion(models.Model):
ciudad = models.CharField(max_length=50, null=True, choices=Ciudades_a_elegir, default="Ninguna")
nombre = models.CharField(max_length=20, null=True, choices=Competiciones_a_elegir, default="Ninguna")
titulo = models.CharField(max_length=40, null=True)
fecha = models.DateField(null=True)
participantes = models.IntegerField(null=True)
flyer = models.ImageField(null=True, upload_to='imagenes', default='Ninguna')
def __str__(self):
return self.nombre + " " + self.titulo
class Participante(models.Model):
competicion = models.ForeignKey(Competicion, on_delete=models.CASCADE, null=True, blank=True)
participantes = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
def __str__(self):
return self.competicion.nombre + " " + self.competicion.titulo
forms.py
class ParticipanteForm(ModelForm):
class Meta:
model = Participante
exclude = ['competicion', 'participantes']
views.py
def competiciones(request):
qs = Competicion.objects.all()
form = ParticipanteForm(request.POST or None)
if form.is_valid():
nombres = form.save()
nombres.competicion = ???#Help me
nombres.participantes = request.user
nombres.save()
return redirect('home')
context = {
'object_list':qs,
'form':form,
}
return render(request, "competiciones.html", context)
template
{% for i in object_list %}
<ul>
<li>{{i.nombre}}</li>
<li>{{i.ciudad}}</li>
<li>{{i.titulo}}</li>
<li>{{i.fecha}}</li>
<li>{{i.participantes}}</li>
{% if i.flyer %}
<img src="{{i.flyer.url}}" width="100px" >
{% endif %}
<li><form action="" method="POST">
{% csrf_token %}
<p> {{ form.competicion}} </p>
<p>{{form.participantes}}</p>
<input type="submit" name="Inscribirse" value="Inscribirse">
</form> </li>
</ul>
{% endfor %}
This is only like 1 course. In number one there is the different fields of the Competicion Model. And number two is the button of the form to the Participante Model, which fields are hidden and take the id of the course and the user. So I have a lot of these both courses displayed in the web. The function of the Particpante Model is to store the people who register in the course and the course itself.
def competiciones(request):
qs = Competicion.objects.all()
form = ParticipanteForm(request.POST or None)
if form.is_valid():
data = form.save()
data.participantes_id = request.user
for i in qs:
data.competicion_id = i.id
data.save()
return redirect('home')

Django form to formset

I'm currently learning Django forms and I came across this post.
One of the forms currently looks like this:
What I'd like to do is to change Category into a formset and be able to render multiple dropdowns while creating a product.
My models.py:
class Category(models.Model):
name = models.CharField(max_length=30)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=30)
price = models.DecimalField(decimal_places=2, max_digits=10)
category = models.ForeignKey(Category, on_delete = models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.name
My forms.py:
class CategoryForm(forms.ModelForm):
class Meta:
model = Category
fields = ('name', )
class ProductForm(forms.ModelForm):
class Meta:
model = Product
fields = ('name', 'price', 'category', )
def __init__(self, user, *args, **kwargs):
super(ProductForm, self).__init__(*args, **kwargs)
self.fields['category'].queryset = Category.objects.filter(user=user)
Current method in views.py:
#login_required
def new_product(request):
if request.method == 'POST':
form = ProductForm(request.user, request.POST)
if form.is_valid():
product = form.save(commit=False)
product.user = request.user
product.save()
return redirect('products_list')
else:
form = ProductForm(request.user)
return render(request, 'products/product_form.html', {'form': form})
products_form.html:
{% extends 'base.html' %}
{% block content %}
<h1>New product</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="save">
cancel
</form>
{% endblock %}
What I tried is to make use of the modelformset_factory and change the method in views.py by creating a CategoryFormSet as:
CategoryFormSet = modelformset_factory(Category, fields=('name', ), extra=2)
formset = CategoryFormSet(data=data, queryset=Category.objects.filter(user=request.user))
then replacing the original form from views.py with the created formset. In the html I simply replace the {{form}} with {{formset}}. After playing around with it for a while, I either get the New product with just a submit button (no form rendered) or a User object has no attribute GET error. What am I doing wrong?
The tutorial focuses on allowing the user to add/update more instances of one model. You want to edit one thing, with multiple related things inline.
However, your data model only allows one category per product, so this does not make any sense. Whether you want more than one category per product, is something only you can answer :) - I'm going to assume you want that.
First you need to change your model to allow for multiple categories per product:
class Product(models.Model):
name = models.CharField(max_length=30)
price = models.DecimalField(decimal_places=2, max_digits=10)
categories = models.ManyToManyField(Category, related_name='products')
user = models.ForeignKey(User, on_delete=models.CASCADE)
And then you need to learn about Inline Formsets.
Come back with a specific if you get stuck on that.
Instead of creating new model Category. You can do this.
CATEGORY_CHOICES= (
("1", "1"),
("2", "2"),
("3", "3"),
("4", "4"),
("5", "5"),
("6", "6"),
("7", "7"),
("8", "8"),
)
category = models.CharField(max_length = 20,choices = CATEGORY_CHOICES,default = '1')
It will automatically render in HTML.

How to display A only a users entered data related in a foreignkey on detailview in django

I am building this simple quiz app. This app allows all users to submit an answer to an assignment in Docx format. I what that any time a user views the question on the DetailView page, if the user has already submitted a solution for that assignment, that solution should be shown on the DetailView page as well. Current I get is all that answers submitted by all users. I only want a user's answer to that assignment on the detailpage
this is my model.
class Assignment(models.Model):
title = models.CharField(max_length=120)
slug = models.SlugField(max_length=500)
course = models.ForeignKey(Course, on_delete=models.CASCADE)
class_or_level = models.ForeignKey(StudentClass, on_delete=models.CASCADE)
teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE)
Text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
date_expire = models.DateTimeField()
def __str__(self):
return self.title
class Answer(models.Model):
slug = models.SlugField(max_length=500)
assignment = models.ForeignKey(Assignment, on_delete=models.CASCADE)
student = models.ForeignKey(User, on_delete=models.CASCADE)
file = models.FileField(upload_to='assignment')
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '{} - {} '.format(self.assignment, self.student)
Below is my view
class AssignmentSubmitView(DetailView):
model = Assignment
template_name = 'assignment_submit.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['student_answer'] = self.object.answer_set.all()
return context
Below is my filter on detailview template.
{% for answer in student_answer %}
{{ answer.file }}
{% endfor %}
You will need to first of all know the user that is accessing that page, so i presume you have a user model and an authentication system in place.
in the views
class AssignmentSubmitView(DetailView):
model = Assignment
template_name = 'assignment_submit.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['student_answer'] = self.object.answer_set.filter()#then filter and get the answer specific to that user here (depending on your user and Assignment models)
return context
and in your templates
{% if user.is_authenticated %}
{% if student_answer %}
{% for answer in student_answer %}
{{ answer.file }}
{% endfor %}
{% endif %}
{% endif %}

Compare user attributes in template using IF statement

I have a list of users and want to display their tasks only if the selected user belongs to the same department. My Models have a department field that I want to compare.
This is my template code.
{% extends 'view_users.html' %}
{% block view_user_tasks %}
Back
<p> todo lists for {{ user }}</p>
{% for todo in view_user_tasks %}
<a id="{{todo.id}}" class="todo_remove"></a>
{% endfor %}
{% endblock view_user_tasks %}
What i want to do is evaluate this condition:
if request.user.Department == user.Department:
show user tasks
This are my respective views.
class ViewUsers(ListView):
model = CustomUser
template_name = 'view_users.html'
class ViewUserTasks(ListView):
model = Todo
template_name = 'view_user_tasks.html'
context_object_name = 'view_user_tasks'
My models.py
class Todo(models.Model):
title = models.CharField(max_length=30)
body = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True, blank=True)
checked = models.BooleanField(default=False)
owner = models.ManyToManyField(CustomUser)
id = HashidAutoField(primary_key=True)
def __str__(self):
return "%s: %s" % (self.title, self.body)
class CustomUser(AbstractUser):
Department = models.CharField(max_length=30, blank=True)
How can I be able to accomplish this?
Do your filtering logic in the view. You can override the default get_queryset method and return only the Todos that you want.
class ViewUserTasks(ListView):
template_name = 'view_user_tasks.html'
context_object_name = 'view_user_tasks'
def get_queryset(self):
return Todo.objects.filter(user__Department=self.request.user.Department)
And then just loop through the returned data like you are already doing.
If I clearly understand your question, you can compare it like this:
{% if todo.user.id == user.id %}