So I have a model fie, a forms.py file and a views.py file. The views file returns a detail view of a post, now I wish to add a model form of a comments model into the detail view so I can access it in d template as {{ form }}. I can do this with function-based views but finding it difficult to do with class-based views. Here are the code.
#models.py
from django.db import models
from django.contrib.auth.models import User
class Post(models.Model):
title = models.CharField(max_length=50)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
date_posted = models.DateTimeField(default=timezone.now)
likes = models.ManyToManyField(User, blank=True, related_name='post_likes')
image = models.ImageField(null=False, blank=False, upload_to='post_images')
slug = models.SlugField(unique=True)
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
text = models.CharField(max_length=150)
date_commented = models.DateTimeField(auto_now_add=True)
comment_by = models.ForeignKey(User, on_delete=models.CASCADE)
#forms.py
from django import forms
from users.models import Profile
from Post.models import Comment
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['text', ]
#views.py
from django.views.generic import ListView, DetailView
class PostDetail(DetailView):
model = Post
template_name = 'Post/blog-detail.html'
Hope my question makes sense Thanks.
You can do it, for example:
class PostDetail(DetailView):
model = Post
template_name = 'Post/blog-detail.html'
def get_context_data(self, **kwargs):
context = super(PostDetail, self).get_context_data(**kwargs)
context['comment_form'] = CommentForm()
return context
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 am trying to join two tables and serialize them as an API. I have referred to the docs of the Django rest framework and tried a code. It didn't work. Could not resolve the problem even after trying so many times. I am trying to get a JSON file like
{
'album_name': 'The Grey Album',
'artist': 'Danger Mouse',
'tracks': [
{'order': 1, 'title': 'Public Service Announcement'},
{'order': 2, 'title': 'What More Can I Say'},
{'order': 3, 'title': 'Encore'},
...
],
}
But what I get is
{
'album_name': 'The Grey Album',
'artist': 'Danger Mouse',
}
This is the model file I am using
Model.py
from django.db import models
from django.contrib.auth.models import User
STATUS_CHOICE = (
('simple', 'simple'),
('intermediate', 'intermediate'),
)
class Quiz(models.Model):
quiz_name = models.CharField(max_length=1000)
video_id = models.ForeignKey("youtube.Youtube", on_delete=models.CASCADE)
questions_count = models.IntegerField(default=0)
description = models.CharField(max_length=70, null=True)
created = models.DateTimeField(auto_now_add=True)
slug = models.SlugField()
pass_mark = models.IntegerField()
class Meta:
ordering = ['created']
def __str__(self):
return self.quiz_name
class Category(models.Model):
category = models.CharField(max_length=20, choices=STATUS_CHOICE, default='simple')
quiz_id = models.ForeignKey(Quiz, on_delete=models.CASCADE)
def __str__(self):
return self.category
class Questions(models.Model):
quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE)
question = models.CharField(max_length=1000)
mark = models.IntegerField()
def __str__(self):
return self.question
class Choice(models.Model):
question = models.ForeignKey(Questions, on_delete=models.CASCADE)
choice_1 = models.CharField(max_length=1000)
choice_2 = models.CharField(max_length=1000)
choice_3 = models.CharField(max_length=1000)
choice_4 = models.CharField(max_length=1000)
answer = models.CharField(max_length=1000, default=choice_1)
def __str__(self):
return self.answer
Serializer.py
from rest_framework import serializers
from rest_framework.permissions import IsAuthenticated
from .models import Category, Quiz, Questions, Choice
from django.contrib.auth import authenticate
from django.contrib.auth.hashers import make_password
class QuizSerializer(serializers.ModelSerializer):
class Meta:
model = Quiz
fields = '__all__'
class QuestionsSerializer(serializers.ModelSerializer):
class Meta:
model = Questions
fields = '__all__'
class ChoiceSerializer(serializers.ModelSerializer):
class Meta:
model = Choice
fields = '__all__'
class CategorySerializer(serializers.ModelSerializer):
quiz_name = QuizSerializer(read_only=True)
class Meta:
model = Category
fields = ['id','category','quiz_name']
View.py
from rest_framework import generics, permissions, mixins
from rest_framework.response import Response
from .serializer import CategorySerializer
from .models import Category
class ViewQuiz(generics.ListCreateAPIView):
permission_classes = [
permissions.AllowAny,
]
queryset = Category.objects.all()
serializer_class = CategorySerializer
def list(self, request):
queryset = self.get_queryset()
serializer = CategorySerializer(queryset, many=True)
print(serializer.data)
return Response(serializer.data)
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ['id','category','quiz_id']
def to_representation(self, instance):
response = super().to_representation(instance)
response['quiz_id'] = QuizSerializer(instance.quiz_id).data
return response
This will produce the result you want, I made an change in how the serializer represent the data. I have some of my serializer doing the same, but my views are working a bit different from yours.
Looks like you are trying to get questions serializes in quiz.
To do that you need to:
1. In Questions model include related_name in quiz field:
class Questions(models.Model):
quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE, related_name="questions")
question = models.CharField(max_length=1000)
mark = models.IntegerField()
def __str__(self):
return self.question
In QuizSerializer include questions field and set many to True:
class QuizSerializer(serializers.ModelSerializer):
questions = QuestionsSerializer(source="questions", many=True)
class Meta:
model = Quiz
fields = ("questions", ... other needed fields)
Include source attribute in QuizSerializer in CategorySerializer:
class CategorySerializer(serializers.ModelSerializer):
quiz_name = QuizSerializer(read_only=True, source="quiz_id")
class Meta:
model = Category
fields = ['id', 'category', 'quiz_name']
Your Quiz was not serialized because the relation between Category and Quiz in tables are called quiz_id but your field is called quiz_name, so the framework did not know where it should take quiz, because it was looking at quiz_name relation which does not exist.
modelForm got an unexpected argument 'initial' I am getting this error. please can anyone explain how to solve this ?
Here is my model.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, default=None)
StudentID = models.CharField(max_length=8, blank=False, unique=True)
Branch = models.CharField(max_length=255,choices=Departments,default="CSE")
def __str__(self):
return f'{self.user.username} Profile'
class complaintForm(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE)
category = models.CharField(max_length=255,choices=complaints,default='Mess')
title = models.CharField(max_length=20)
content = models.CharField(max_length=100)
image = models.ImageField(upload_to='complaint_pics/')
def __str__(self):
return self.title
form.py
class complaintForm(forms.ModelForm):
class Meta:
model = complaintForm
fields = ['title','content','image',]
views.py
class CreateComplaintView(CreateView):
model = complaintForm
form_class = complaintForm
template_name = 'user/post_complaint.html'
success_url = 'success'
You passed your model to the form attribute. This is why ComplaintForm is not a good idea for a model name. You better rename this to Complaint for example:
class Complaint(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE)
category = models.CharField(max_length=255,choices=complaints,default='Mess')
title = models.CharField(max_length=20)
content = models.CharField(max_length=100)
image = models.ImageField(upload_to='complaint_pics/')
def __str__(self):
return self.title
You will need to construct and run migrations to rename the table at the database side.
Then you thus define your form as:
from app.models import Complaint
class ComplaintForm(forms.ModelForm):
class Meta:
model = Complaint
fields = ['title','content','image',]
Finally in your CreateView, you can use:
from app.models import Complaint
from app.forms import ComplaintForm
class CreateComplaintView(CreateView):
model = Complaint
form_class = ComplaintForm
template_name = 'user/post_complaint.html'
success_url = 'success'
def form_valid(self, form):
form.instance.user = self.request.user.profile
super().form_valid(form)
Note: normally a Django models, just like all classes in Python are given a name in PerlCase, not snake_case, so it should be: Complaint instead of complaint.
I registred Category admin in models.py. I added that model in Post model via ForenKey. But when i log into admin console i cannot see my Categories, I just see Category Object(1), Category Object(2) and so on.
I will provide you a print screen and a code.
http://prntscr.com/nxt25y
instead if Japanese Kitchen or any other category (im working blog for chef),
i see Category Object, the one that i highlighted on printscreen.
I think its not a big deal but i didnt worked on django for quite some time so i forgot a lot.
Can you spot a mistake?
Thanks guys
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils.text import slugify
from ckeditor_uploader.fields import RichTextUploadingField
class Category(models.Model):
name = models.CharField(max_length=150)
slug = models.SlugField(max_length=150)
class Meta:
ordering = ('name',)
verbose_name = 'catergory'
verbose_name_plural = 'catergories'
def __str__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length=100)
slug = models.SlugField(
help_text="A short label, generally used in URLs.", default='', max_length=100)
category = models.ForeignKey(
Category, on_delete=models.CASCADE, default='New category')
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
content = RichTextUploadingField(blank=True, null=True)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
ordering = ['-date_posted']
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('detail', kwargs={'slug': self.slug})
def __str__(self):
return self.title
this is admin.py
from .models import Post, Category
from django.forms import ModelForm
from django.contrib.admin import ModelAdmin
from suit_ckeditor.widgets import CKEditorWidget
class PostForm(ModelForm):
class Meta:
widgets = {
'name': CKEditorWidget(editor_options={'startupFocus': True})
}
class CategoryAdmin(admin.ModelAdmin):
list_display = ('name', 'slug')
prepopulated_fields = {'slug': ('name',)}
admin.site.register(Category, CategoryAdmin)
class PostAdmin(admin.ModelAdmin):
form = PostForm
list_display = ['title', 'slug', 'date_posted', 'author']
list_filter = ['title', 'date_posted']
prepopulated_fields = {'slug': ('title',)}
admin.site.register(Post, PostAdmin)
You need to override __str__ method in your models to handle what you intend to display on admin.
class Category(models.Model):
name = models.CharField(max_length=150)
slug = models.SlugField(max_length=150)
class Meta:
ordering = ('name',)
verbose_name = 'catergory'
verbose_name_plural = 'catergories'
def __str__(self):
return self.name
Originally started here: Django IN query as a string result - invalid literal for int() with base 10
I have a number of apps within my site, currently working with a simple "Blog" app. I have developed a 'Favorite' app, easily enough, that leverages the ContentType framework in Django to allow me to have a 'favorite' of any type... trying to go the other way, however, I don't know what I'm doing, and can't find any examples for.
I'll start off with the favorite model:
favorite/models.py
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.contrib.auth.models import User
class Favorite(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
user = models.ForeignKey(User)
content_object = generic.GenericForeignKey()
class Admin:
list_display = ('key', 'id', 'user')
class Meta:
unique_together = ("content_type", "object_id", "user")
Now, that allows me to loop through the favorites (on a user's "favorites" page, for example) and get the associated blog objects via {{ favorite.content_object.title }}.
What I want now, and can't figure out, is what I need to do to the blog model to allow me to have some tether to the favorite (so when it is displayed in a list it can be highlighted, for example).
Here is the blog model:
blog/models.py
from django.db import models
from django.db.models import permalink
from django.template.defaultfilters import slugify
from category.models import Category
from section.models import Section
from favorite.models import Favorite
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
class Blog(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=140, editable=False)
author = models.ForeignKey(User)
homepage = models.URLField()
feed = models.URLField()
description = models.TextField()
page_views = models.IntegerField(null=True, blank=True, default=0 )
created_on = models.DateTimeField(auto_now_add = True)
updated_on = models.DateTimeField(auto_now = True)
def __unicode__(self):
return self.title
#models.permalink
def get_absolute_url(self):
return ('blog.views.show', [str(self.slug)])
def save(self, *args, **kwargs):
if not self.slug:
slug = slugify(self.title)
duplicate_count = Blog.objects.filter(slug__startswith = slug).count()
if duplicate_count:
slug = slug + str(duplicate_count)
self.slug = slug
super(Blog, self).save(*args, **kwargs)
class Entry(models.Model):
blog = models.ForeignKey('Blog')
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=140, editable=False)
description = models.TextField()
url = models.URLField(unique=True)
image = models.URLField(blank=True, null=True)
created_on = models.DateTimeField(auto_now_add = True)
def __unicode__(self):
return self.title
def save(self, *args, **kwargs):
if not self.slug:
slug = slugify(self.title)
duplicate_count = Entry.objects.filter(slug__startswith = slug).count()
if duplicate_count:
slug = slug + str(duplicate_count)
self.slug = slug
super(Entry, self).save(*args, **kwargs)
class Meta:
verbose_name = "Entry"
verbose_name_plural = "Entries"
Any guidance?
The django doc on it is here: Reverse generic relations. Basically on the Blog model itself you can add a GenericRelation...
class Blog(models.Model):
favorites = generic.GenericRelation(Favorite)
For a given blog you can find all of the Favorite models that are associated with it...
b = Blog.objects.get(slug='hello-world-blog-slug')
all_blog_favorites = b.favorites.objects.all()
Or see if the current user has the blog favorited...
user_has_blog_favorited = b.favorites.objects.filter(user=request.user).exists()