I am attempting to use two detail views that will render different templates for the same model, at different URLs of course. Is it possible to have different generic detail views for the same model? If not I'll just have to write my own I suppose. All my detail views route to the absoluteurl but in this case I want each detail view to route to the template I have defined in the class.
I used the method below to successfully create multiple list views and update views, but it just doesn't work on detail views, I always end up at "course_detail" even though I declared "course_detail_producer_view."
models.py
class Course(models.Model):
class Meta:
verbose_name = "Course"
verbose_name_plural = "Courses"
ordering = ['start_time']
pub_partner_choices = [
("company1", "company1"),
('company2', 'company2'),
]
status_choices = [
('hold', 'Hold'),
('editorial', 'Editorial'),
('approved', 'Approved'),
('cancelled', 'Cancelled'),
]
title = models.CharField(max_length=200)
slug = AutoSlugField(max_length=100, help_text="course title",
populate_from=['title', 'date'], unique=True, )
start_time = models.TimeField(blank=True, null=True)
end_time = models.TimeField(blank=True, null=True)
date = models.DateField(blank=True, null=True)
new_course = models.BooleanField(default=False)
new_instructor = models.BooleanField(default=False)
katacoda = models.BooleanField(default=False)
jupyterhub = models.BooleanField(default=False)
released = models.BooleanField(default=False)
status = models.CharField(max_length=50,
choices=status_choices,
blank=False
)
pub_partner = models.CharField(max_length=50,
choices=pub_partner_choices,
blank=False)
course_notes = models.TextField(max_length=500,
blank=True,
)
producer_notes = models.TextField(max_length=500, blank=True)
id = models.UUIDField(primary_key=True, default=uuid.uuid4,
editable=False
)
producer = models.ManyToManyField(Producer,
related_name="course",
blank=True,
)
def get_absolute_url(self):
"""Return URL to detail page of a Course"""
return reverse(
"course_detail",
kwargs={"slug": self.slug}
)
def __str__(self):
date_time = f"{self.date} {self.start_time}"
return f"{self.title} : {date_time}"
urls.py
path(
'courses/<str:slug>/',
CourseDetail.as_view(),
name='course_detail'
),
path(
'courses/producer-view/<str:slug>/',
CourseDetailProducerView.as_view(),
name='course_detail_producer_view'
),
views.py
class CourseDetail(LoginRequiredMixin, DetailView):
queryset = Course.objects.all()
template_name = 'lots_app/course_detail.html'
class CourseDetailProducerView(LoginRequiredMixin, DetailView):
queryset = Course.objects.all()
template_name = 'lots_app/course_detail_producer_view.html'
My problem was being caused by an UpdateView that was using reverse_lazy to get the absolute_url. It turns out there was no problems with the DetailViews, just how I was trying to get to them (whoops!) The solution was to override get_success_url(). The now corrected UpdateView looks like this:
class CourseUpdateProducerView(LoginRequiredMixin, UpdateView):
form_class = CourseFormProducerView
model = Course
template_name = 'lots_app/course_form_producer_view.html'
extra_context = {"update": True}
def get_success_url(self, **kwargs):
"""Return the URL to redirect to after processing a valid form."""
url = reverse_lazy('course_detail_producer_view',
kwargs={"slug": self.object.slug})
return url
Related
# models.py
class NewBlank(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=50)
description = models.CharField(max_length=100, blank=True)
blank_on_off = models.BooleanField(default=False)
create_date = models.DateTimeField(auto_now_add=True)
update_date = models.DateTimeField(auto_now=True)
class BlankContent(models.Model):
refer = models.TextField()
memo = models.TextField()
new_blank = models.ForeignKey('NewBlank', on_delete=models.CASCADE, related_name='blankcontent')
# views.py
class BlankDetail(LoginRequiredMixin, DetailView):
model = NewBlank
template_name = 'blank_app/blank_detail.html'
context_object_name = 'blank'
class BlankContentCreate(CreateView):
model = BlankContent
fields = "__all__"
template_name = 'blank_app/new_blank_content_create.html'
def get_success_url(self):
return reverse_lazy('blank_detail', kwargs={'pk': self.object.new_blank.pk})
# urls.py
urlpatterns = [
path('blank/<int:pk>/', BlankDetail.as_view(), name='blank_detail'),
path('new-blank-content/', BlankContentCreate.as_view(), name='blank_content_create'),
]
There is a creativeview in the detail view and I want to create a model in the detailview when I press it. So even if I don't specify the new_blank part, I want it to be filled automatically according to the pk in the detailview, what should I do?
In case you want to perform some extra work in your DetailView, one of the ways to do that would be to override the get_object method.
from django.views.generic import DetailView
class BlankDetail(LoginRequiredMixin, DetailView):
model = NewBlank
template_name = 'blank_app/blank_detail.html'
context_object_name = 'blank'
def get_object(self):
obj = super().get_object()
# do your thing with obj.pk
pk = self.kwargs.get('pk') # in case you want to access the `pk` from URL
I'm working on a Comment app and I would like my Commentserializer to display the exact URL of each instance of Comment. I know that I have to use the get_absolute_url of the Comment model. But i cannot connect my viewnames from my router to the get_absolute_url.
Here is my Model :
class Comment(models.Model):
content = models.TextField(max_length=150)
author = models.ForeignKey(
User,
on_delete = models.CASCADE
)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField(blank=True)
content_object = GenericForeignKey('content_type', 'object_id')
parent = models.ForeignKey(
"self",
on_delete = models.CASCADE,
blank=True,
null=True
)
datestamp = models.DateTimeField(auto_now_add=True)
objects = CommentManager()
def __str__(self):
return str(self.content[:30])
def save(self):
self.object_id = self.parent.id
super(Comment, self).save()
def children(self):
return Comment.objects.filter(parent=self)
def get_absolute_url(self):
return reverse("comments-details", args=[str(self.id)])
#property
def is_parent(self):
if self.parent is None:
return False
return True
and here is my router :
router = router = routers.SimpleRouter()
router.register('api/comments', CommentViewSet)
urlpatterns = router.urls
As you can see, I'm trying to use "comment-details" as a viewname.
The end Goal is to display a JSON like that :
{ url : 'blabla/comments/{pk}/details }
Okay It was easy to fix. Just use a HyperlinkedModelSerializer and add 'url' to your fields like so :
class CommentSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Comment
fields = [
"url",
"datestamp",
"content",
"is_parent",
"object_id",
"children"
]
I'm looking for a way to bring data from one model into a view of another model for a ListView. Basically, when the user opens up the listview of the vocabulary model, I need to look up and pull out the associated pinyin field from the dictionary model by using the vocab field. There is some example code at the bottom of the codeview that would be how I would match up a Vocabulary.vocab with a Dictionary.pinyin.
############### Models
class Vocabulary(models.Model):
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
vocab = models.CharField(max_length=255, blank=False, null=False)
translation = models.CharField(max_length=255, blank=False, null=False)
level = models.PositiveSmallIntegerField(blank=True, null=True, choices=LEVELS, default=0)
audio = models.URLField(blank=True, null=True)
objects = RandomManager()
class Meta:
constraints = [
models.UniqueConstraint(fields=['created_by', 'vocab'], name='User Vocab Duplicate Check')
]
verbose_name = "Chinese Vocabulary"
verbose_name_plural = verbose_name
# this function will be invoked when this model object is foreign key of other model(for example Employee model.).
def __str__(self):
return self.vocab
class Dictionary(models.Model):
traditional = models.CharField(max_length=20)
simplified = models.CharField(max_length=20)
pinyin = models.CharField(max_length=255)
simplified_radical = models.CharField(max_length=20)
hsk_level = models.PositiveSmallIntegerField(blank=True, null=True, choices=LEVELS, default=0)
frequency_rank = models.PositiveIntegerField(blank=True, null=True)
phrase_url = models.CharField(max_length=200)
radical_url = models.CharField(max_length=200)
definition = models.TextField()
objects = RandomManager()
class Meta:
verbose_name = "Dictionary"
verbose_name_plural = "Dictionary"
def __str__(self):
return self.simplified
################# Views
class VocabDetailView(LoginRequiredMixin, DetailView):
model = Vocabulary
template_name = 'library/vocab_details.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['dictionary'] = Dictionary.objects.get(simplified=self.object.vocab)
return context
class VocabListView(LoginRequiredMixin, ListView):
model = Vocabulary
template_name = 'library/vocab_list.html'
paginate_by = 50
def get_queryset(self):
return Vocabulary.objects.filter(created_by=self.request.user)
'''
hao = Vocabulary.objects.get(vocab='你')
haodict = Dictionary.objects.get(simplified=hao.vocab)
haopin = hao_dict.pinyin
'''
If you objects were related, you could override the get_queryset to use select_related or similar in order to get the related objects. But it doesn't look like you can do that because the objects aren't related.
So you could either not use a ListView and gather your objects in the context, or override the context to get the Dictionary objects you want. Sounds like you'd do something like;
def get_context_data(**kwargs):
context = super().get_context_data(**kwargs)
dicts = Dictionary.objects.filter(pinyin__in=self.object_list.values_list('vocab', flat=True))
context['dictionaries'] = dicts
return context
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'
https://github.com/nathanborror/django-basic-apps/blob/master/README.rst I am trying to implement this blog module my question is that the i am writing one generic function and when i fetch a blog get a url as
def Myfunc(request):
p = Post.objects.get(pk=12)
p.get_absolute_url //This prints blog/2011/jun/13/fgfgf/
My question is that how to get the url with the domain name or where does this being handled in the code..
EDIT: i.e, http://mysite.com/blog/2011/jun/13/fgfgf/
The models field is as,
class Post(models.Model):
"""Post model."""
STATUS_CHOICES = (
(1, _('Draft')),
(2, _('Public')),
)
title = models.CharField(_('title'), max_length=200)
slug = models.SlugField(_('slug'), unique_for_date='publish')
author = models.ForeignKey(User, blank=True, null=True)
body = models.TextField(_('body'), )
tease = models.TextField(_('tease'), blank=True, help_text=_('Concise text suggested. Does not appear in RSS feed.'))
status = models.IntegerField(_('status'), choices=STATUS_CHOICES, default=2)
allow_comments = models.BooleanField(_('allow comments'), default=True)
publish = models.DateTimeField(_('publish'), default=datetime.datetime.now)
created = models.DateTimeField(_('created'), auto_now_add=True)
modified = models.DateTimeField(_('modified'), auto_now=True)
categories = models.ManyToManyField(Category, blank=True)
#created_by = models.ForeignKey(UserProfile)
tags = TagField()
objects = PublicManager()
class Meta:
verbose_name = _('post')
verbose_name_plural = _('posts')
db_table = 'blog_posts'
ordering = ('-publish',)
get_latest_by = 'publish'
def __unicode__(self):
return u'%s' % self.title
#permalink
def get_absolute_url(self):
return ('blog_detail', None, {
'year': self.publish.year,
'month': self.publish.strftime('%b').lower(),
'day': self.publish.day,
'slug': self.slug
})
You can use the sites framework to get the fully qualified url - as per https://docs.djangoproject.com/en/1.2/ref/contrib/sites/