django one template - many views - beginner - python

I have managed (with a lot of assistance) to create a basic test blog in django 1.4.6 and python 2.7.
I can display the blog entries as a list (main page) and then allow the user to view each individual blog entry by clicking on the blog entry link.
I am now attempting to display the blog entries by author and by archive (by the published date of the blog entry).
Is it possible to have the one blog page that can list the blogs by date (most recent first), by author and by archive (by the date - most recent last)?
I am assuming the code is written in the urls.py and views.py files with the output to the single blog page, but I haven't yet found an example to work from and I can't quite figure this out on my own.
Here is my models.py:
class BlogPostDetails(models.Model, FillableModelWithLanguageVersion):
blog_post_title = models.CharField(max_length=50)
blog_post_date_published = models.DateField()
blog_post_author = models.CharField(max_length=25)
blog_post_body = models.TextField()
blog_post_allow_comments = models.BooleanField(default=False)
blog_post_timestamp_added = models.DateTimeField(auto_now_add=True, auto_now=False)
blog_post_timestamp_updated = models.DateTimeField(auto_now=True, auto_now_add=False)
def __unicode__(self):
return self.blog_post_title
class Meta:
ordering = ['-blog_post_date_published']
verbose_name = ('Blog')
verbose_name_plural = ('Blogs')
Here is my views.py:
def blog_post_item(request, blog_posts_id):
blog_posts = BlogPostDetails.objects.get(pk=blog_posts_id)
language_versions = get_language_versions(user=request.user)
return render(request, 'core/details/blog/blog_item.html', {
'blog_posts': blog_posts,
'display_default_language': display_default_language(request.user),
'languages': LANGUAGES,
'language_versions': language_versions,
'language_versions_num': len(language_versions),
})
def blog_post_list(request):
blog_posts = BlogPostDetails.objects.filter(blog_post_date_published__lt=datetime.today())
language_versions = get_language_versions(user=request.user)
return render(request, 'core/details/blog/blog_list.html', {
'blog_posts': blog_posts,
'display_default_language': display_default_language(request.user),
'languages': LANGUAGES,
'language_versions': language_versions,
'language_versions_num': len(language_versions),
})
Here is my urls.py
url(r'^details/blog/blog_list/$', 'blog_post_list', name='blog_post_list'),
url(r'^details/blog/blog_item/(?P<blog_posts_id>\d+)/$', 'blog_post_item', name='blog_post_item'),

Some advices:
You shouldn't use model name prefix in model field names, as you see code look much better:
class BlogPost(models.Model, FillableModelWithLanguageVersion):
title = models.CharField(max_length=50)
date_published = models.DateField()
author = models.CharField(max_length=25)
body = models.TextField()
allow_comments = models.BooleanField(default=False)
timestamp_added = models.DateTimeField(auto_now_add=True, auto_now=False)
timestamp_updated = models.DateTimeField(auto_now=True, auto_now_add=False)
def __unicode__(self):
return self.title
class Meta:
ordering = ['-date_published']
verbose_name = ('Blog')
verbose_name_plural = ('Blogs')
Update django up to 1.6
User class-based views(filtering and ordering example)
And yes - it is posible to use one template for you task
You should pass order type as url parameter.
url(r'^details/blog/blog_list/(?P<order_type>\w+)/$', 'blog_post_list', name='blog_post_list'),
def blog_post_list(request, order_type='date_published'):
blog_posts = BlogPost.objects.filter(date_published__lt=datetime.today()).order_by(order_type)
language_versions = get_language_versions(user=request.user)
return render(request, 'core/details/blog/blog_list.html', {
'blog_posts': blog_posts,
'display_default_language': display_default_language(request.user),
'languages': LANGUAGES,
'language_versions': language_versions,
'language_versions_num': len(language_versions),
})
If you want to use one url - the only way that i see is javascript on page ordering.

Related

Django - Sending post request using a nested serializer with many to many relationship. Getting a [400 error code] "This field may not be null] error"

I'm fairly new to Django and I'm trying to make a POST request with nested objects. This is the data that I'm sending:
{
"id":null,
"deleted":false,
"publishedOn":2022-11-28,
"decoratedThumbnail":"https://t3.ftcdn.net/jpg/02/48/42/64/360_F_248426448_NVKLywWqArG2ADUxDq6QprtIzsF82dMF.jpg",
"rawThumbnail":"https://t3.ftcdn.net/jpg/02/48/42/64/360_F_248426448_NVKLywWqArG2ADUxDq6QprtIzsF82dMF.jpg",
"videoUrl":"https://www.youtube.com/watch?v=jNQXAC9IVRw",
"title":"Video with tags",
"duration":120,
"visibility":1,
"tags":[
{
"id":null,
"videoId":null,
"videoTagId":42
}
]
}
Here's a brief diagram of the relationship of these objects on the database
I want to create a video and pass in an array of nested data so that I can create multiple tags that can be associated to a video in a many to many relationship. Because of that, the 'id' field of the video will be null and the 'videoId' inside of the tag object will also be null when the data is being sent. However I keep getting a 400 (Bad request) error saying {tags: [{videoId: [This field may not be null.]}]}
I'm trying to override the create method inside VideoManageSerializer so that I can extract the tags and after creating the video I can use that video to create those tags. I don't think I'm even getting to the create method part inside VideoManageSerializer as the video is not created on the database. I've been stuck on this issue for a few days. If anybody could point me in the right direction I would really appreciate it.
I'm using the following serializers:
class VideoManageSerializer(serializers.ModelSerializer):
tags = VideoVideoTagSerializer(many=True)
class Meta:
model = Video
fields = ('__all__')
# POST
def create(self, validated_data):
tags = validated_data.pop('tags')
video_instance = Video.objects.create(**validated_data)
for tag in tags:
VideoVideoTag.objects.create(video=video_instance, **tag)
return video_instance
class VideoVideoTagSerializer(serializers.ModelSerializer):
class Meta:
model = VideoVideoTag
fields = ('__all__')
This is the view which uses VideoManageSerializer
class VideoManageViewSet(GenericViewSet, # generic view functionality
CreateModelMixin, # handles POSTs
RetrieveModelMixin, # handles GETs
UpdateModelMixin, # handles PUTs and PATCHes
ListModelMixin):
serializer_class = VideoManageSerializer
queryset = Video.objects.all()
These are all the models that I'm using:
class Video(models.Model):
decoratedThumbnail = models.CharField(max_length=500, blank=True, null=True)
rawThumbnail = models.CharField(max_length=500, blank=True, null=True)
videoUrl = models.CharField(max_length=500, blank=True, null=True)
title = models.CharField(max_length=255, blank=True, null=True)
duration = models.PositiveIntegerField()
visibility = models.ForeignKey(VisibilityType, models.DO_NOTHING, related_name='visibility')
publishedOn = models.DateField()
deleted = models.BooleanField(default=0)
class Meta:
managed = True
db_table = 'video'
class VideoTag(models.Model):
name = models.CharField(max_length=100, blank=True, null=True)
deleted = models.BooleanField(default=0)
class Meta:
managed = True
db_table = 'video_tag'
class VideoVideoTag(models.Model):
videoId = models.ForeignKey(Video, models.DO_NOTHING, related_name='tags', db_column='videoId')
videoTagId = models.ForeignKey(VideoTag, models.DO_NOTHING, related_name='video_tag', db_column='videoTagId')
class Meta:
managed = True
db_table = 'video_video_tag'
I would consider changing the serializer as below,
class VideoManageSerializer(serializers.ModelSerializer):
video_tag_id = serializers.PrimaryKeyRelatedField(
many=True,
queryset=VideoTag.objects.all(),
write_only=True,
)
tags = VideoVideoTagSerializer(many=True, read_only=True)
class Meta:
model = Video
fields = "__all__"
# POST
def create(self, validated_data):
tags = validated_data.pop("video_tag_id")
video_instance = Video.objects.create(**validated_data)
for tag in tags:
VideoVideoTag.objects.create(videoId=video_instance, videoTagId=tag)
return video_instance
Things that have changed -
Added a new write_only field named video_tag_id that supposed to accept "list of PKs of VideoTag".
Changed the tags field to read_only so that it won't take part in the validation process, but you'll get the "nested serialized output".
Changed create(...) method to cooperate with the new changes.
The POST payload has been changed as below (note that tags has been removed and video_tag_id has been introduced)
{
"deleted":false,
"publishedOn":"2022-11-28",
"decoratedThumbnail":"https://t3.ftcdn.net/jpg/02/48/42/64/360_F_248426448_NVKLywWqArG2ADUxDq6QprtIzsF82dMF.jpg",
"rawThumbnail":"https://t3.ftcdn.net/jpg/02/48/42/64/360_F_248426448_NVKLywWqArG2ADUxDq6QprtIzsF82dMF.jpg",
"videoUrl":"https://www.youtube.com/watch?v=jNQXAC9IVRw",
"title":"Video with tags",
"duration":120,
"visibility":1,
"video_tag_id":[1,2,3]
}
Refs
DRF: Simple foreign key assignment with nested serializer?
DRF - write_only
DRF - read_only

add url for category with django 2

I'm working on my blog page
basically the blog has category for split the same posts,
for this
I made a class for category and made a relationship between the category and my post class like this :
class Category(models.Model):
name = models.CharField(max_length=256)
def __str__(self):
return self.name
class Post(models.Model):
image = models.ImageField(upload_to='Posts_image')
title = models.CharField(max_length=256)
configure_slug = models.CharField(max_length=512)
slug = models.SlugField(max_length=512,null=True,blank=True)
content = HTMLField('Content')
date = models.DateTimeField(auto_now_add=True)
categories = models.ManyToManyField(Category)
tags = TaggableManager()
publish = models.BooleanField(default=False)
def __str__(self):
return self.title
after this I made this function
def blog_category(request):
res_posts = Post.objects.all()
category = request.POST.get('categories__name')
if category:
res_post = res_post.filter(
Q(categories__name__icontains=category)).distinct()
context = {
'posts':res_posts,
}
return render(request, 'Blog/category-result.html', context)
I tell you how its works:
when the users click on the one of category title in the blog page
this functions start work and search how many posts has this category title and list them in the category-result.html
but this function doesn't work correctly
I think this code doesn't work correctly
category = request.POST.get('categories__name')
request.Post can't take the categories__name when user click
Can you help me for this problem???
As you said the user clicks I'm assuming the category title links to a something like http://your.site/your-view?categories__name=selected-category, if that's the case what you need to use is request.GET not request.POST.

Django-Rest: Serialising ListField() - '_TaggableManager' object is not iterable

My goal is to add tags to a post. I'm using latest taggit (Requirement: Django-Taggit https://github.com/alex/django-taggit ) and DRF.
Goal: To pop tags only from posted request. For each tag in the post request to call post.tags.add("tag1","tag2") to add these tags to the model.
Currently, my post serialiser is:
class PostSerializer(serializers.ModelSerializer):
tags = serializers.ListField(
child=serializers.CharField(min_length=0, max_length=30)
)
...
def create(self, validated_data):
pub.set_trace()
tags_data = validated_data.pop('tags') # Need to pop tags only
# to_be_tagged, validated_data = self._pop_tags(validated_data)
images_data = self.context.get('view').request.FILES
post = Post.objects.create(**validated_data)
post.tags.add(*tags_data)
for image_data in images_data.values():
PostImage.objects.create(post=post, image=image_data)
return post
When I send a post request with the following data:
data = { 'title': 'First Post',
...
'tags':'["tag1"]'}
I get an error:
Exception Value: '_TaggableManager' object is not iterable
I also tried sending 'tags':'one, two, three' and simply one
Edit - PDB output:
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
> /Users/gr/Desktop/PycharmProjects/godo/api/serializers.py(112)create()
-> tags_data = validated_data.pop('tags')
(Pdb) tags_data
*** NameError: name 'tags_data' is not defined
(Pdb)
Models.py
from taggit.managers import TaggableManager
class Post(models.Model):
objects = LocationManager() # to sort by distance
tags = TaggableManager()
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=False)
description = models.TextField(max_length=500, blank=False)
def __str__(self):
return '{}'.format(self.title)
Are you sure about the content of tags_data variable? Could you put there traceback and debug it (see: using (i)pdb for debugging)?
I think wrong is these line:
post.tags.add(tags_data)
lets try:
post.tags.add(*tags_data)
The star unpack list. See these answer for reference: https://stackoverflow.com/a/4959580/953553
In my project I ma handling tags which are in model M2M and in serializer I decided to use this approach:
tags = serializers.SlugRelatedField(
many=True,
queryset=Tag.objects.all(),
slug_field='text'
)
my models:
class Spot(models.Model):
tags = models.ManyToManyField(Tag, related_name='spot_facilities', null=True, blank=True)
class Tag(models.Model):
text = models.CharField(max_length=100, unique=True)

how to save Many to Many relationship in django

How to create an object for a Django model with a many to many field?
From above question i come to know we can save Many to Many field later only.
models.py
class Store(models.Model):
name = models.CharField(max_length=100)
class Foo(models.Model):
file = models.FileField(upload_to='')
store = models.ManyToManyField(Store, null=True, blank=True)
views.py
new_track.file = request.FILES['file']
new_track.save()
And file uploading working fine then later i modify my code to add store then i am here...
Now i am sure db return id's here. Then i tried with my below code but that's given me error only
x = new_track.id
new = Foo.objects.filter(id=x)
new.store.id = request.POST['store']
new.save()
ok so the error here is 'QuerySet' object has no attribute 'store'
And also i tried with add that's now working either.
So the question is how to save()
the right way of saving objects with manytomany relations would be:
...
new_track.file = request.FILES['file']
new_track.save()
new_store = Store.objects.get(id=int(request.POST['store']))
new_track.store.add(new_store)
As of 2020, here's my approach to saving ManyToMany Field to a given object.
Short Answer
class HostingRequestView(View):
def post(self, request, *args, **kwargs):
form = VideoGameForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.updated_by = request.user
obj.save()
selected_categories = form.cleaned_data.get('category') #returns list of all selected categories e.g. ['Sports','Adventure']
#Now saving the ManyToManyField, can only work after saving the form
for title in selected_categories:
category_obj = Category.objects.get(title=title) #get object by title i.e I declared unique for title under Category model
obj.category.add(category_obj) #now add each category object to the saved form object
return redirect('confirmation', id=obj.pk)
Full Answer
models.py
class Category(models.Model):
title = models.CharField(max_length=100, null=True, unique=True)
class VideoGame(models.Model):
game_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50, blank=False, null=False)
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=False, on_delete=models.CASCADE)
category = models.ManyToManyField(Category) #ManyToMany Category field
date_added = models.DateTimeField(auto_now_add=True, verbose_name="date added")
forms.py ModelForm
class VideoGameForm(forms.ModelForm):
CATEGORIES = (
('Detective', 'Detective'),
('Sports', 'Sports'),
('Action', 'Action'),
('Adventure', 'Adventure'),
)
category = forms.MultipleChoiceField(choices=CATEGORIES, widget=forms.SelectMultiple())
class Meta:
model = VideoGame
fields = ['name', 'category', 'date_added']
views.py on POST
class HostingRequestView(View):
def post(self, request, *args, **kwargs):
form = VideoGameForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.updated_by = request.user
obj.save()
selected_categories = form.cleaned_data.get('category') #returns list of all selected categories e.g. ['Sports','Adventure']
#Now saving the ManyToManyField, can only work after saving the form
for title in selected_categories:
category_obj = Category.objects.get(title=title) #get object by title i.e I declared unique for title under Category model
obj.category.add(category_obj) #now add each category object to the saved form object
return redirect('confirmation', id=obj.pk)
URL path for redirect
urlpatterns = [
path('confirmation/<int:id>/', Confirmation.as_view(), name='confirmation'),
]
I hope this can be helpful. Regards
new.stores.all()
returns all stores linked to the object.
Maybe:
Change Foo to Tracks
Tracks.objects.filter(id=x) to Tracks.objects.get(id=x)
Let me know how it goes
why this confusion so much.. you are getting the id there then, call the store like
new_track.save()
new_track.store.add(request.POST['store'])

How to create Views with less queries in django

Models.py
class Book(models.Model):
created_at = models.DateTimeField(auto_now_add=True, editable=False)
name = models.CharField(max_length=255, unique=True)
slug = models.SlugField(max_length=255, blank=True, default='', unique=True)
class BookTranslation(models.Model):
book = models.ForeignKey(Book, related_name='book_translations')
language = models.CharField(max_length=2, choices=LANGUAGE_CHOICES)
class Chapter(models.Model):
chapter = models.IntegerField()
book_translation = models.ForeignKey(BookTranslation, related_name='related_chapters')
class Page(models.Model):
chapter = models.ForeignKey(Chapter, related_name='related_pages')
page = models.IntegerField()
url = models.CharField(max_length=255)
urls.py
url(r'^(?P<language>[\w-]{2})-book/(?P<slug>[\w-]+)/(?P<chapter>\d+)/(?P<page>\d+)/$",
PageView(),
name="page")
I tried different approaches to make PageView() and ended up with this:
class PageView(DetailView):
model = Book
template_name = 'bookinfo/book_page.html'
context_object_name = 'book'
def get_context_data(self, **kwargs):
context = super(PageView, self).get_context_data(**kwargs)
context['book_translation'] = BookTranslation.objects.get(
book=context['book'], language=self.kwargs['language'])
context['chapter'] = Chapter.objects.get(
book_translation=context['book_translation'].id, chapter=self.kwargs['chapter'])
context['page'] = Page.objects.get(
chapter=context['chapter'].id, page=self.kwargs['page'])
context['chapter_list'] = Chapter.objects.filter(
book_translation=context['book_translation'].id)
context['page_list'] = Page.objects.filter(
chapter=context['chapter'].id)
return context
But this way, every time i open this page, i make 6 requests to the DB, when i could easily get the arguments in context['book'], context['book_translation'] context['chapter'] and context['page'] with a singole SQL query like this:
SELECT *
FROM Book b, BookTranslation bt, Chapter c, Page p
WHERE b.slug=self.kwargs['slug'] and
b.name=bt.book_id and
bt.language=self.kwargs['language'] and
c.book_translation_id=bt.id and
c.chapter=self.kwargs['chapter'] and
c.id=p.chapter_id and
p.page=self.kwargs['page']
Can someone explain me how can i make this View(preferably class based) more performance? I probably didn't understand how they work...
If you want to retrieve related foreign keys use select_related by overriding get_queryset of SingleObjectMixin as follows:
class PageView(DetailView):
...
def get_queryset(self, *args, **kwargs):
qs = super(PageView, self).get_queryset(*args, **kwargs)
return qs.select_related()
This will fetch all related objects in a single query, so as long as the queryset is not evaluated, all the related objects in your view's get_context_data should not be queried again.
Refer: https://docs.djangoproject.com/en/1.6/ref/models/querysets/#select-related

Categories