Wrong text in selects - django

I have these model and admin files. It works nice but when I select one activity while adding new Gym Object in the select I see "Activity object" instead of the Activity title.
How can I change these?
# Model
from django.db import models
class Activity(models.Model):
title = models.CharField(max_length=250)
description = models.CharField(max_length=250)
class Gym(models.Model):
name = models.CharField(max_length=250)
pub_date = models.DateTimeField('date published')
where = models.CharField(max_length=250)
description = models.TextField()
timetable = models.TextField()
activities = models.ManyToManyField(Activity, through='GymActivity')
class GymActivity(models.Model):
gym = models.ForeignKey(Gym)
activity = models.ForeignKey(Activity)
# Admin
from django.contrib import admin
from gym.models import Gym, Activity, GymActivity
class GymActivityInline(admin.TabularInline):
model = Gym.activities.through
extra = 6
class GymAdmin(admin.ModelAdmin):
list_display = ['name', 'pub_date']
fieldsets = [
(None, {'fields': ['name']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
(None, {'fields': ['where']}),
(None, {'fields': ['description']}),
(None, {'fields': ['timetable']}),
]
inlines = [GymActivityInline]
class ActivityAdmin(admin.ModelAdmin):
list_display = ['title']
admin.site.register(Gym, GymAdmin)
admin.site.register(Activity, ActivityAdmin)

You are missing __unicode__ method on the models
Do this:
class Activity(models.Model):
title = models.CharField(max_length=250)
description = models.CharField(max_length=250)
def __unicode__(self):
return u'%s' % self.title
If you are using Python 3.x, just replace __unicode__ with __str__

Related

how to build a get_absolute_url with year, month, day and slug on Djano Rest Framework

I'm building a blog aplication with DRF, and I want it to be able to get my get_absolute_url method for each post, like: http://127.0.0.1:8001/blog/posts/2022/10/11/my-post
And not the default: http://127.0.0.1:8001/blog/posts/1
Here's my model:
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'Draft'), ('published', 'Published')
)
title = models.CharField(max_length=250)
slug = models.SlugField(unique_for_date='publish', max_length=250)
body = models.TextField()
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='blog_posts')
publish = models.DateTimeField(default=timezone.now)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
category = models.ForeignKey(Category, on_delete=models.SET_NULL, related_name="posts" ,blank=True, null=True )
objects = models.Manager()
published = PublishedManager()
tags = TaggableManager()
feature_image = models.ImageField(upload_to="uploads/", null=True, blank=True)
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', args=[self.publish.year,
self.publish.month,
self.publish.day,
self.slug], )
And my serializer:
class BlogSerializer(serializers.HyperlinkedModelSerializer):
author = serializers.ReadOnlyField(source='author.username')
url = serializers.CharField(source='get_absolute_url', read_only=True)
class Meta:
model = Post
fields = ['url', 'id', 'title', 'slug', 'body', 'author', 'publish', 'created_at', 'updated_at',
'status', 'category', 'feature_image']
Somebody help how to do that, please.
thanks!
Edit:
This is the error that I get when running the app:
NoReverseMatch at /blog/posts/
Reverse for 'post-detail' with arguments '(2022, 10, 11, 'first-post-2')' not found. 2 pattern(s) tried: ['blog/posts/(?P[^/.]+)\.(?P[a-z0-9]+)/?$', 'blog/posts/(?P[^/.]+)/$']
From what you've posted and what I've seen you don't seem to be doing anything wrong.
Could you describe what that spits out?- is it crashing?- is the url wrong?- does it need the website prefix?
I've also seen this, /, which might be a route you could take. (I've done this with custom admin pages)
class BlogSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.SerializerMethodField()
def get_url(self, obj):
return obj.get_absolute_url()
class Meta:
model = Post
fields = ['url', 'id', 'title', 'slug', 'body', 'author', 'publish', 'created_at', 'updated_at',
'status', 'category', 'feature_image']
Edit
Yeah, that looks like a problem with your Urls. the Docs show this:
from django.urls import path
from . import views
urlpatterns = [
path('articles/2003/', views.special_case_2003),
path('articles/<int:year>/', views.year_archive),
path('articles/<int:year>/<int:month>/', views.month_archive),
path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]
So your path might end up like:
Note: Idk what that last one is supposed to be, I just put title.. you use slug for any string, if you end up doing a pk instead use int
urlpatterns = [
path('posts/<int:year>/<int:month>/<int:day>/<slug:title>/', views.post_detail),
]

Django duplicate queries

I'm trying to optimize my django app using select and prefetch related but for some reason it doesn't work
this is my models :
class Question(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(blank=True, default='avatar.png')
and this is my serializers :
class EagerLoadingMixin:
#classmethod
def setup_eager_loading(cls, queryset):
if hasattr(cls, "_SELECT_RELATED_FIELDS"):
queryset = queryset.select_related(*cls._SELECT_RELATED_FIELDS)
if hasattr(cls, "_PREFETCH_RELATED_FIELDS"):
queryset = queryset.prefetch_related(*cls._PREFETCH_RELATED_FIELDS)
return queryset
class QuestionSerializer(EagerLoadingMixin, serializers.ModelSerializer):
profile = serializers.SerializerMethodField()
class Meta:
model = Question
fields = (
'id',
'title',
'author',
'profile',
'content',
)
_SELECT_RELATED_FIELDS = ['author']
_PREFETCH_RELATED_FIELDS = ['author__profile']
#staticmethod
def get_profile(obj):
profile = Profile.objects.get(user=obj.author)
return ProfileSerializer(profile).data
but that's what I get in django debug toolbar:
SELECT ••• FROM "accounts_profile" WHERE "accounts_profile"."user_id" = 14 LIMIT 21`
and 10 similar queries.

How to fix django admin "add" button

I'm new to web development, and i'm building a blog web app in Django.
I'm having problems adding new posts through django-admin. Clicking the "add" button gives me an "Error during template rendering - 'str' object has no attribute 'utcoffset'" error message.
models.py
from django.db import models
from django.utils import timezone
import datetime
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=50)
content = models.TextField(blank=True, null=True)
post_date = models.DateTimeField(default='date posted')
def published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.post_date <= now
published_recently.admin_order_field = 'post_date'
published_recently.boolean = True
published_recently.short_description = 'Recent post?'
def __str__(self):
return self.title
class Customer(models.Model):
username = models.CharField(max_length=50)
firstname = models.CharField(max_length=50)
lastname = models.CharField(max_length=50)
email = models.CharField(max_length=50)
country = models.CharField(max_length=50)
reg_date = models.DateTimeField(default='date reg')
def __str__(self):
return self.username
class Comment(models.Model):
comment_cont = models.TextField(max_length=200)
user_name = models.ForeignKey(Customer, default=0, on_delete=models.CASCADE)
comment_post = models.ForeignKey(Post, on_delete=models.CASCADE)
votes = models.BigIntegerField(default=0)
comment_date = models.DateTimeField(default='date commented')
def __str__(self):
return self.comment_cont
class Feedback(models.Model):
feedback_title = models.CharField(max_length=50)
feedback_detail = models.CharField(max_length=200)
user_name = models.ForeignKey(Customer, default=1, verbose_name='user_name', on_delete=models.SET_DEFAULT)
admin.py
from django.contrib import admin
from .models import Post, Customer, Feedback, Comment
# Register your models here.
class CommentInLine(admin.TabularInline):
model = Comment
extra = 1
fields = ['comment_cont', 'votes', 'comment_date']
class CustomerAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['firstname', 'lastname', 'username', 'email', 'country', 'reg_date']})
]
class PostAdmin(admin.ModelAdmin):
fieldsets = [
('Post', {'fields': ['title', 'content']}),
('Date information', {'fields': ['post_date'], 'classes':['collapse']}),
]
inlines = [CommentInLine]
list_display = ('title', 'content', 'post_date', 'published_recently')
list_filter = ['post_date']
search_fields = ['title']
class FeedbackAdmin(admin.ModelAdmin):
fieldsets = [
('Feedback', {'fields': ['feedback_title', 'feedback_detail', 'user_name']}),
]
list_display = ('user_name', 'feedback_title', 'feedback_detail')
# inlines = [CustomerInLine]
# list_display = ('user_name', 'feedback_title', 'feedback_detail')
class CommentAdmin(admin.ModelAdmin):
fields = ['user_name', 'comment_post', 'comment_cont', 'votes', 'comment_date']
admin.site.register(Post, PostAdmin)
admin.site.register(Feedback, FeedbackAdmin)
admin.site.register(Customer, CustomerAdmin)
admin.site.register(Comment, CommentAdmin)
I want to be able to add posts through Django admin. Any other corrections to the code is highly welcome. I appreciate the help. Thanks.
post_date = models.DateTimeField(default='date posted')
the post_date is DateTimeField and you have provided a string as default . It should be an instance of datetime.datetime.
post_date = models.DateTimeField(default=timezone.now)
# or
post_date = models.DateTimeField(auto_now_add=True, verbose_name='Publish Time')
should fix the problem

Django: url instead of image in Admin

I need to show a image preview (small size image) of my order_item in admin.
I'm basically following these other question/answer here:
Django Admin Show Image from Imagefield
However, I cannot get the desired results. I'm getting this instead:
I though it was maybe the URL, but the relative path of that file is the same (except for the static part):
static/media/images/python.png
What could be wrong?
models.py:
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
product = models.CharField(max_length= 200)
quantity = models.CharField(max_length= 200)
size = models.CharField(max_length=200)
price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name= 'PEN Price')
image = models.ImageField(upload_to='images', blank=True, null=True)
comment = models.CharField(max_length=200, blank=True, null=True, default='')
uploaded_at = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = "OrderItem"
def image_thumbnail(self):
return u'<img src="%s" />' % (self.image.url)
image_thumbnail.short_description = 'Image Thumbnail'
image_thumbnail.allow_tags = True
def sub_total(self):
return self.quantity * self.price
admin.py
# Register your models here.
class OrderItemAdmin(admin.TabularInline):
model = OrderItem
fieldsets = [
# ('Customer', {'fields': ['first_name', 'last_name'], }),
('Product', {'fields': ['product'],}),
('Quantity', {'fields': ['quantity'],}),
('Price', {'fields': ['price'], }),
('Image', {'fields': ['image'], }),
('Image_Thumbnail', {'fields': ['image_thumbnail'], }),
]
readonly_fields = ['product', 'quantity', 'price', 'image', 'image_thumbnail']
can_delete = False
max_num = 0
template = 'admin/order/tabular.html'
### Order Display ###
#admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
model = Order
list_display = ['id', 'first_name', 'last_name', 'email', 'total', 'reason', 'created']
list_editable = ['reason',]
list_display_links = ('id', 'email')
search_fields = ['token', 'shipping_department', 'email']
readonly_fields = ['id','created']
fieldsets = [
('ORDER INFORMATION', {'fields': ['id','token', 'total', 'created']}),
# ('BILLING INFORMATION', {'fields': ['billingName', 'billingAddress1', 'billingCity', 'billingPostCode',
# 'billingCountry', 'emailAddress']}),
('SHIPPING INFORMATION', {'fields': ['first_name', 'last_name', 'shipping_address', 'shipping_department', 'shipping_province',
'shipping_district', 'shipping_address1', 'shipping_address2']}),
]
inlines = [
OrderItemAdmin,
]
def has_delete_permission(self, request, obj=None):
return False
def has_add_permission(self, request):
return False
From Django 1.9, allow_tags has been deprecated, instead you can use mark_safe:
From documentation:
In older versions, you could add an allow_tags attribute to the method to prevent auto-escaping. This attribute is deprecated as it’s safer to use format_html(), format_html_join(), or mark_safe() instead.
So, try like this:
from django.utils.html import mark_safe
...
def image_thumbnail(self):
return mark_safe('<img src="%s" />' % (self.image.url))

How to delete products from inventory in Django?

What I want: I have the model classes named Book and Issue. In Book, there is a field named quantity that defines how many books are there. When the Admin issue a book to a student, there will be a -1 in quantity. how may I implement this. N.B: I want to implement this in Django Admin Dashboard
from django.db import models
from datetime import date, timedelta, datetime
# Create your models here.
class User(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
depertment_name = models.CharField(max_length=30)
roll_number = models.CharField(max_length=10, primary_key=True)
semester = models.CharField(max_length=10)
def __str__(self):
return self.depertment_name.upper() + ', ' + self.roll_number + ', ' + self.first_name.upper()
class Book(models.Model):
name = models.CharField(max_length=30)
author_name = models.CharField(max_length=30)
category = models.CharField(max_length=30)
quantity = models.IntegerField()
def __str__(self):
return self.name
class Issue(models.Model):
issue_id = models.CharField(max_length=10)
roll = models.ForeignKey(User, on_delete=models.CASCADE)
book_name = models.ForeignKey(Book, on_delete=models.CASCADE)
issue_date = models.DateField(auto_now=False, auto_now_add=True)
def return_date(self):
return datetime.now()+timedelta(days=3)
def fine(self):
return_date = datetime.now() + timedelta(days=3)
if datetime.now() > return_date:
return 'Fine'
else:
return 'No Fine'
UPDATE: IMPLEMENTATION IS SOLVED. NEED TO SHOW RESULT
please take a look here
ADMIN.PY CODE
from django.contrib import admin
from django.contrib.auth.models import Group
from .models import User, Book, Issue
admin.site.site_header = 'Library Management System'
class UserAdmin(admin.ModelAdmin):
list_display = ('roll_number', 'first_name', 'last_name', 'depertment_name')
list_filter = ('depertment_name', 'semester')
search_fields = ('roll_number', 'first_name')
class BookAdmin(admin.ModelAdmin):
list_display = ('name', 'author_name', 'remaining', 'category')
list_filter = ('category', 'author_name')
search_fields = ('name', 'author_name')
class IssueAdmin(admin.ModelAdmin):
list_display = ('issue_id', 'issue_date', 'return_date', 'fine', 'save')
list_filter = ('issue_date',)
search_fields = ('issue_id',)
admin.site.register(User, UserAdmin)
admin.site.register(Book, BookAdmin)
admin.site.register(Issue, IssueAdmin)
admin.site.unregister(Group,)
I think, overriding save() method of Issue model would solve the problem,
class Issue(models.Model):
# your code
def save(self, *args, **kwargs):
if not self.pk:
super().save(*args, **kwargs)
self.book_name.quantity -= 1
self.book_name.save()
else:
super().save(*args, **kwargs)
Update-1
Inorder to get see the quantity of books, use book_name__quantity in list_display of IssueAdmin.
class IssueAdmin(admin.ModelAdmin):
list_display = ('issue_id', 'issue_date', 'return_date', 'fine', 'book_name__quantity')
list_filter = ('issue_date',)
search_fields = ('issue_id',)