I am having an issue with an url and regular expression I get the error
AttributeError: Generic detail view EmployeeDetailView must be called with either an object pk or a slug.
What I am to achieve is to get to a user detail page coming from a specific project
url(r'^project/(?P<pk>[0-9]+)/$',views.ProjectDetailView.as_view(), name='ProjectDetails'),
url(r'^project/(?P<pk1>[0-9]+)/(?P<pk2>[0-9]+)/$',views.EmployeeDetailView.as_view(), name='EmployeDetails'),
my view is :
Project detail :
class ProjectDetailView(generic.DetailView, LoginRequiredMixin):
#import pdb; pdb.set_trace()
model = Project
template_name = 'project_details.html'
def get_context_data(self, **kwargs):
context = super(ProjectDetailView, self).get_context_data(**kwargs)
try:
team_name = Project.objects.get(id=self.kwargs['pk']).team_id.members.all()
context['team_name'] = team_name
except AttributeError:
pass
return context
class EmployeeDetailView(generic.DetailView, LoginRequiredMixin):
#import pdb; pdb.set_trace()
model = MyUser
template_name = 'Employee_Details.html'
def get_context_data(self, **kwargs):
context = super(EmployeeDetailView, self).get_context_data(**kwargs)
employee_name = MyUser.objects.get(id=self.kwargs['pk'])
context['employee_name'] = employee_name
return context
HTML link :
<span class="fa fa-id-card-o" aria-hidden="true"> Show Results
models:
MyUser models:
class MyUser(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
first_name = models.CharField(max_length=150, blank=True, null=True)
last_name = models.CharField(max_length=150, blank=True, null=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_hr = models.BooleanField(default=False)
is_candidate = models.BooleanField(default=False)
is_employee = models.BooleanField(default=False)
company = models.CharField(max_length=100, blank=True, null=True)
Project model:
class Project(models.Model):
name = models.CharField(max_length=250)
team_id = models.ForeignKey(Team, blank=True, null=True)
project_hr_admin = models.ForeignKey('registration.MyUser', blank=True, null=True)
candidat_answers = models.ManyToManyField('survey.response')
Team models:
class Team(models.Model):
team_name = models.CharField(max_length=100, default = '')
team_hr_admin = models.ForeignKey(MyUser, blank=True, null=True)
members = models.ManyToManyField(MyUser, related_name="members")
could you please help me to figure it ? thx you ;)
Django doesn't know how to use pk1 and pk2 to fetch the object for the view. I would override the get_object method and fetch the object there.
from django.shortcuts import get_object_or_404
# Note mixin should come first
class EmployeeDetailView(LoginRequiredMixin, generic.DetailView):
model = MyUser
template_name = 'Employee_Details.html'
def get_object(self, queryset=None):
return get_object_or_404(MyUser, pk=self.kwargs['pk2'], project=self.kwargs['pk1'])
...
Another option is to set pk_url_kwarg = 'pk2'. This tells Django that pk2 is the primary key of the MyUser object, so there is no need to override get_object. However if you do this, then Django will ignore the pk1 from the URL.
class EmployeeDetailView(generic.DetailView, LoginRequiredMixin):
#import pdb; pdb.set_trace()
model = MyUser
pk_url_kwarg = 'pk2'
template_name = 'Employee_Details.html'
Related
I'm looking to connect two SQLite tables together (oh dear).
I found this solution : How to use django models with foreign keys in different DBs? , I adapted it to my models and my code (I think). I have no bad answers from django. However, I would like to modify the entry with the admin view of django, and when I try to add the entry with the foreign key of another database, I get this answer:
Exception Type: OperationalError at /admin/users/character/add/
Exception Value: no such table: books
How to adapt to fix it?
models database default
from django.db import models
from users.related import SpanningForeignKey
from books.models import Books
class Character(models.Model):
last_name = models.fields.CharField(max_length=100)
first_name = models.fields.CharField(max_length=100)
book = SpanningForeignKey('books.Books', null=True, on_delete=models.SET_NULL)
def __str__(self):
return f'{self.first_name} {self.last_name}'
models external database
from django.db import models
# Create your models here.
class Books(models.Model):
title = models.TextField()
sort = models.TextField(blank=True, null=True)
timestamp = models.TextField(blank=True, null=True) # This field type is a guess.
pubdate = models.TextField(blank=True, null=True) # This field type is a guess.
series_index = models.FloatField()
author_sort = models.TextField(blank=True, null=True)
isbn = models.TextField(blank=True, null=True)
lccn = models.TextField(blank=True, null=True)
path = models.TextField()
flags = models.IntegerField()
uuid = models.TextField(blank=True, null=True)
has_cover = models.BooleanField(blank=True, null=True)
last_modified = models.TextField() # This field type is a guess.
class Meta:
managed = False
db_table = 'books'
app_label = 'books'
class Languages(models.Model):
lang_code = models.TextField()
class Meta:
managed = False
db_table = 'languages'
app_label = 'books'
class BooksLanguagesLink(models.Model):
book = models.ForeignKey(Books, null=True, on_delete=models.SET_NULL, db_column='book')
lang_code = models.ForeignKey(Languages, null=True, on_delete=models.SET_NULL, db_column='lang_code')
item_order = models.IntegerField()
class Meta:
managed = False
db_table = 'books_languages_link'
app_label = 'books'
admin books
from django.contrib import admin
from books.models import Books, Languages
class BooksModelAdmin(admin.ModelAdmin):
using = 'calibre_db'
def save_model(self, request, obj, form, change):
obj.save(using=self.using)
def delete_model(self, request, obj):
obj.delete(using=self.using)
def get_queryset(self, request):
return super().get_queryset(request).using(self.using)
def formfield_for_foreignkey(self, db_field, request, **kwargs):
return super().formfield_for_foreignkey(db_field, request, using=self.using, **kwargs)
def formfield_for_manytomany(self, db_field, request, **kwargs):
return super().formfield_for_manytomany(db_field, request, using=self.using, **kwargs)
# Register your models here.
admin.site.register(Books, BooksModelAdmin)
I have a model form that creates a new job entry, and on submission, I need an invisible field job_time_estimation to be set to a sum of 'service_stats_estimate_duration' values from ServiceItemStats objects associated with the JobEntry by a many-to-many relationship when submitting the form.
For example, if in my NewJobEntryForm I chose two existing ServiceItemStats objects that have service_stats_estimate_duration values 60 and 90, on submission, I want a value 150 to be saved in that JobEntry object's job_time_estimation attribute.
I tried doing this using aggregation by defining a save() method in the model but I am getting an error "name 'serviceItemStats' is not defined".
I am not sure if I am going about this the right way. Any help would be appreciated.
My code:
models.py:
class ServiceItemStats(models.Model):
service_stats_name = models.CharField(primary_key=True, max_length=20)
service_stats_estimate_duration = models.IntegerField()
# Many-to-many relationship with JobEntry.
def __str__(self):
return self.service_stats_name
class JobEntry(models.Model):
# PK: id - automatically assigned by Django.
jo
b_entry_date_time = models.DateTimeField(default=timezone.now)
jo
b_date = models.DateField(blank=True, null=True)
job_checked_in = models.BooleanField()
job_checked_out = models.BooleanField(default=False)
job_priority = models.IntegerField()
job_time_estimation = models.IntegerField(blank=True, null=True)
job_comments = models.TextField(max_length=200, blank=True, null=True)
job_parts_instock = models.BooleanField(default=False)
job_started = models.BooleanField(default=False)
job_finished = models.BooleanField(default=False)
job_expand_fault_evidence = models.ImageField(blank=True, null=True)
job_expand_comments = models.ImageField(blank=True, null=True)
job_expand_parts_required = models.CharField(max_length=200, blank=True, null=True)
vehicle = models.ForeignKey(Vehicle, on_delete=models.CASCADE) #One-to-one relationship
customer = models.ForeignKey(Customer, on_delete=models.CASCADE) #One-to-one relationship
serviceBay = models.ForeignKey(ServiceBay, on_delete=models.CASCADE, blank=True, null=True) #One-to-one relationship
serviceItemStats = models.ManyToManyField(ServiceItemStats, blank=True) #Many-to-many relationship
def __str__(self):
return self.id
def save(self, *args, **kwargs):
if not self.job_time_estimation:
self.job_time_estimation = serviceItemStats.objects.all().aggregate('service_stats_estimate_duration')
return super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse("jobs:job_detail",kwargs={'pk':self.pk})
views.py
class JobCreateView(FormView):
template_name = "jobs/jobentry_form.html"
form_class = NewJobEntryForm
success_url = reverse_lazy("jobs:job_list")
def form_valid(self, form):
form.save()
return super(job_list, self).form_valid(form)
forms.py
class NewJobEntryForm(ModelForm):
class Meta:
model = JobEntry
fields = ['vehicle', 'customer', 'job_date', 'job_checked_in', 'job_priority', 'job_comments', 'job_parts_instock', 'serviceItemStats']
widgets = {
'job_date' : forms.DateInput(format=('%m/%d/%Y'), attrs={'class':'form-control', 'placeholder':'Select a date', 'type':'date'}),
'ServiceItemStats' : forms.CheckboxSelectMultiple(),
'job_priority' : forms.RadioSelect(choices=priorityOptions),
}
You can try this.
from django.db.models import Sum
class JobCreateView(FormView):
template_name = "jobs/jobentry_form.html"
form_class = NewJobEntryForm
success_url = reverse_lazy("jobs:job_list")
def form_valid(self, form):
job=form.save()
estimation = job.serviceItemStats.all().aggregate(total=Sum('service_stats_estimate_duration'))
job.job_time_estimation = estimation['total']
job.save()
return super(job_list, self).form_valid(form)
In my project, How can I get all posts with post_status like- publish, pending, draft, spam.
I want to query with post_status.
Post Model
`
class Post(models.Model):
title = models.CharField(max_length=255)
slug = models.CharField(max_length=255, unique= True, editable=False)
author = models.ForeignKey(User, on_delete=models.CASCADE)
subtitle = models.CharField(max_length=255, null=True, blank=True)
description = models.TextField(max_length=5555, null=True, blank=True)
image = models.ImageField(blank=True, upload_to=post_image_path)
image_caption = models.CharField(max_length=255, blank=True)
post_status = models.CharField(max_length=255)
comment_status = models.CharField(max_length=255)
post_type = models.CharField(max_length=50)
comment_count = models.IntegerField(null=True, blank=True)
categories = models.ManyToManyField(Category, blank=True)
tags = models.ManyToManyField(Tag, blank=True)
createdAt = models.DateTimeField(auto_now_add=True)
updatedAt = models.DateTimeField(auto_now=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
def __str__(self):
return self.title
`
Serializer.py
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
read_only_fields = ['author']
How to implement in view?
The below snippet should work for your query.
class PostListView(generics.ListAPIView):
serializer_class = PostSerializer
def get_queryset(self):
queryset = Post.objects.all()
post_status = self.request.query_params.get('post_status')
if username is not None:
queryset = queryset.filter(post_status=post_status)
return queryset
Snipped adapted from Django Rest Framework - Filtering
views.py
from django.db.models import Q
from .serializers import PostSerializer
from rest_framework.generics import ListAPIView
from .models import Post
class PostListAPIView(ListAPIView):
serializer_class = PostSerializer
def get_queryset(self):
queryset = Post.objects.filter(Q(post_status__contains='publish') | Q(post_status__contains='pending') | Q(post_status__contains='draft') | Q(post_status__contains='spam'))
return queryset
``
I'm trying to build a form that automatically fills some fields in a class based create view that lets logged in users create a Job. However, I can't seem to find the correct way of doing this for fields that aren't the user (eg. request.user).
So the create view is trying to get a company_name from the logged in user, company_name field belongs to a model called Company. Each Company has an owner with a foreign key to the User model. All the reuest I've tried so far have led to a 'WSGIRequest' error.
So far I've tried to request:
company_name
user.company_name
company.company_name
company
user
I don't understand how these requests work, I have seen examples for getting the logged in users name and I'm not familiar how to do this otherwise.
Please can someone help me understand how this works and how I should be doing this?
I'm using Django 2.2 with python 3.6
Auth Models:
class User(AbstractBaseUser, PermissionsMixin):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
phone_number = models.CharField(max_length=15)
email = models.EmailField(max_length=250, unique=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
last_login = models.DateTimeField(null=True, blank=True)
date_joined = models.DateTimeField(auto_now_add=True)
objects = UserManager()
USERNAME_FIELD = 'email'
EMAIL_FIELD = 'email'
def __str__(self):
return self.first_name
def get_absolute_url(self):
return "/users/%i/" % self.pk
class Company(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
company_name = models.CharField(max_length=100, unique=True)
company_address = models.CharField(max_length=100, unique=True)
company_website = models.URLField(blank=True, null=True)
company_verified = models.BooleanField(default=False)
def __str__(self):
return self.company_name
View
class JobCreateView(LoginRequiredMixin, CreateView):
model = Job
form_class = JobForm
template_name = 'jobs/job_create.html'
def form_valid(self, form):
form.instance.company_name = self.request.user
form.instance.job_reference = self.request.job.pk
return super(JobCreateView, self).form_valid(form)
def get_success_url(self):
return reverse('jobs:job_details', kwargs={'pk': self.object.pk})
Other Model:
class Job(models.Model):
JOB_TYPE = (
('1', 'Service'),
('2', 'Repair'),
('3', 'Quotation'),
('4', 'Consultation'),
('5', 'Report'),
('6', 'Design'),
)
ACCOUNT_TYPE = (
('1', 'Existing Customer'),
('2', 'Charge to Account'),
('3', 'New Customer'),
('4', 'Pre-Paid/C.O.D'),
('5', 'Issued and Acc App'),
)
company_name = models.ForeignKey(Company, related_name='jobs', verbose_name="Company Name", on_delete=models.CASCADE)
job_reference = models.CharField(max_length=50, blank=False)
contact_person = models.CharField(max_length=50)
contact_number = models.IntegerField()
contact_person_email = models.EmailField(max_length=100, blank=True, null=True)
site_address = models.CharField(max_length=100)
job_type = models.CharField(choices=JOB_TYPE, max_length=50, default='1')
account_type = models.CharField(choices=ACCOUNT_TYPE, max_length=50, default='1')
job_details = models.CharField(max_length=1000)
created = models.DateTimeField(default=now, blank=True)
def __str__(self):
return str(self.company_name)
def get_absolute_url(self):
return reverse('jobs:detail', kwargs={'pk': self.pk})
For anyone trying to solve a problem like this, the answer is;
Views:
class JobDocketCreate(CreateView):
model = JobDocket
form_class = JobDocketForm
template_name = 'jobs/job_docket_create.html'
def form_valid(self, form):
form.instance.technician = self.request.user
form.instance.job = Job.objects.get(pk=self.kwargs['job_pk'])
print(form.instance.job)
print(form.instance.technician)
context = {'job_pk':self.kwargs['job_pk']}
return super(JobDocketCreate, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(JobDocketCreate, self).get_context_data(**kwargs)
context['job_pk'] = self.kwargs['job_pk']
return context
def get_success_url(self):
return reverse('jobs:my_job_dockets')
Form action in View:
action="{% url 'jobs:create_job_docket' job_pk %}"
I need some help with Django 2 and Python 3.
I'm using a CreateView to add new reccords in my database, but I need to make a filter for my Aviso form page to make the select field (field turma) to show only instances where the representante is the current user.
This is my model:
class Turma(models.Model):
nome = models.CharField(max_length=120, blank=False, null=False, help_text='Obrigatório.')
alunos = models.ManyToManyField(User, help_text='Obrigatório', related_name='alunos_matriculados')
data_cadastro = models.DateField(auto_now_add=True)
representante = models.ForeignKey(User, on_delete=models.PROTECT, blank=False, null=False)
colegio = models.ForeignKey(Colegio, on_delete=models.PROTECT, blank=False, null=False, help_text='Obrigatório.')
class Aviso(models.Model):
data_final = models.DateField(auto_now=False, auto_now_add=False, blank=False, null=False, verbose_name="Data Final")
comentarios = models.TextField(null=True, blank=True)
ultima_modificacao = models.DateField(auto_now=True)
data_post = models.DateField(auto_now_add=True)
turma = models.ForeignKey(Turma, on_delete=models.PROTECT, null=False, blank=False)
materia = models.ForeignKey(Materia, on_delete=models.PROTECT, null=False, blank=False)
This is my view:
class AvisoCreateView(LoginRequiredMixin, CreateView): #Cadastro de Aviso
template_name = 'form.html'
model = models.Aviso
login_url = '/login/'
success_url = reverse_lazy('visualizar_aviso')
fields = [
'turma',
'materia',
'tipo_aviso',
'comentarios',
'data_final'
]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['titulo'] = 'Cadastrar aviso'
context['input'] = 'Adicionar'
return context
How could that be done?
You can add a queryset to the ForeignKey field.
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['form'].fields['turma'].queryset = Turma.objects.filter(representante=self.request.user)
context['titulo'] = 'Cadastrar aviso'
context['input'] = 'Adicionar'
return context
You could create a ModelForm for that model.
And based on this answer you could override the forms __init__() method to alter the fields queryset.
class AvisoForm(forms.ModelForm):
class Meta:
model = Aviso
fields = [
'data_final', 'comentarios', 'ultima_modificacao', 'data_post',
'turma', 'materia',
]
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
# restrict the queryset of 'Turma'
self.fields['turma'].queryset = self.fields['turma'].queryset.filter(
representante=user)
Then, in your view, replace the attribute fields with form_class:
class AvisoCreateView(LoginRequiredMixin, CreateView):
...
form_class = AvisoForm
...
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
Maybe you need to adjust a few things for your specific case.
Let us know if that solved it.