How to generate slug from Chinese text? - django

I am trying to get my admin.py to read Chinese, however I do not know how can I do it. This is what I have.
admin.py
from django.contrib import admin
from collection.models import Thing
class ThingAdmin(admin.ModelAdmin):
model = Thing
list_display = ('name', 'description',)
prepopulated_fields = {'slug': ('name',)}
admin.site.register(Thing, ThingAdmin)
models.py
from django.db import models
class Thing(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
slug = models.SlugField(unique=True)
now I can type it in English and slug will be generated properly, but when I try it in Chinese slug is blank.
any one knows how to do it?? thank you!

I just had similar problem. You need to convert chinese to text that can be stored in SlugField.
Include unidecode and optionally slugify:
from unidecode import unidecode
from django.template.defaultfilters import slugify
And overwrite save to something like this:
class ThingAdmin(admin.ModelAdmin):
model = Thing
list_display = ('name', 'description',)
prepopulated_fields = {'slug': ('name',)}
def save(self, *args, **kwargs):
self.slug = slugify(unidecode(self.name))
return super(ThingAdmin, self).save(*args, **kwargs)
You also need to make sure slug will be always unique, which I do not see in your code.
It will decode name 투자 to this slug tuja, etc.

Related

How to auto-update the slug field in Django admin site?

I know how to auto-populate the slug field of my Blog application from post's title, and it works fine.
But if I edit the title the slug field is not changing.
Is there any way to have it updated automatically?
I use Django's admin site.
Thanks.
from django.utils.text import slugify
class Category(models.Model):
category_name = models.CharField(max_length=100)
slug_category = models.SlugField(default='',editable=False, null=True,blank=True,max_length=250)
def __str__(self):
return "%s" %(self.category_name)
def save(self, *args, **kwargs):
value = self.category_name[0:250]
self.slug_category = slugify(value, allow_unicode=True)
super().save(*args, **kwargs)
May be this is usefull..
#Omid Shojaee- Have a look at the following code. You can use the prepopulated_fields
class CategoryAdmin(admin.ModelAdmin):
list_display = (
"id",
"name",
"slug",
"is_active",
)
prepopulated_fields = {"slug": ("name",)}

Null value in column "user_id" violates not-null constraint in Django 1.9

I have exhausted all avenues in trying to put together a solution for this, but my current knowledge of Python and Django can only get me so far.
I'm creating a basic ticketing system and CreateView used to work until I created a Profile model and then separated the Ticket model into its own app. There were already a couple of tickets created when I refactored my code which is why I know ListView works, DeleteView works as well as DetailView. CreateView works until I hit the save button.
My views and models are below; I hope someone can please help me sort this out.
Ticket Model
from django.db import models
from django.contrib.auth.models import User
....
from qcapp.models import Profile
class Ticket(models.Model):
# Relations
user = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name="tickets", verbose_name="user")
# Attributes
title = models.CharField(max_length=250, verbose_name="Title", help_text="Enter a Ticket Title")
color = models.CharField(max_length=7,
default="#ffffff",
validators=[RegexValidator("(^#[0-9a-fA-F]{3}$)|(^#[0-9a-fA-F]{6}$)")],
verbose_name="Color",
help_text="Enter the hex color code, like #ccc or #cccccc")
description = models.TextField(max_length=1000)
created_date = models.DateTimeField(default=timezone.now, verbose_name='Created Date')
created_by = models.ForeignKey(User, related_name='created_by_user')
# Attributes
# Object Manager
objects = managers.ProjectManager()
# Meta and String
class Meta:
verbose_name = "Ticket"
verbose_name_plural = "Tickets"
ordering = ("user", "title")
unique_together = ("user", "title")
def __str__(self):
return "%s - %s" % (self.user, self.title)
def get_absolute_url(self):
return reverse('ticket_detail', args=[str(self.id)])
Ticket View (CreateView Only)
# -*- coding: utf-8 -*-
...
from django.views.generic import CreateView, UpdateView, DeleteView
...
from .models import Ticket
...
class TicketCreate(CreateView):
model = Ticket
template_name = "tickets/ticket_form.html"
fields = ['title', 'description']
def form_valid(self, form):
form.instance.created_by = self.request.user
return super(TicketCreate, self).form_valid(form)
...
Profile Model(Imported Into Ticket Model)
from django.db import models
from django.conf import settings
from django.contrib.auth.models import User
from django.dispatch import receiver
from django.db.models.signals import post_save
from . import managers
class Profile(models.Model):
# Relations
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="profile", verbose_name="user")
# Attributes
interaction = models.PositiveIntegerField(default=0, verbose_name="interaction")
# Attributes
# Object Manager
objects = managers.ProfileManager()
# Custom Properties
#property
def username(self):
return self.user.username
# Methods
# Meta and String
class Meta:
verbose_name = "Profile"
verbose_name_plural = "Profiles"
ordering = ("user",)
def __str__(self):
return self.user.username
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_for_new_user(sender, created, instance, **kwargs):
if created:
profile = Profile(user=instance)
profile.save()
It looks like you need to add the following to your TicketCreate class in the form_valid function:
form.instance.user = Profile.objects.get(user=self.request.user)
Let me know if that works!

Django utf8 title not showing in admin

I have created this simple model:
from django.db import models
from slugify import *
class News(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
pub_date=models.DateTimeField(auto_now_add=True)
likes = models.IntegerField(default=0)
visits = models.IntegerField(default=0)
slug = models.SlugField()
status = models.BooleanField(default=True)
#approved = models.BooleanField(default=False)
def __unicode__(self):
return unicode(self.title)
def save(self, *args, **kwargs):
self.title = slugify(self.title)
super(News, self).save(*args, **kwargs)
admin.py
from django.contrib import admin
from news.models import News
admin.site.register(News)
Whenever I create a news content in the admin panel with a Persian title, the title does not display on the panel. When the title is in ascii characters, there is not such problem
My Django version is 1.5.5 and mysql database is utf8. I've added this to settings.py (though not sure it is relevant!)
from __future__ import absolute_import, unicode_literals
So appreciate your hints.
I expect the problem is that you're using the slugify function, which explicitly strips out non-ASCII characters.
I'm not sure why you want to slugify the title in the first place, but you might want to look into the new awesome-slugify library, which deals correctly with those characters.

How to generically attach and display tags to models in Django?

I want to write a very basic tagging app in Django that is almost identical to the Generic Foreign Key example in the docs (django-tagging and django-taggit are overblown for me).
The challenge is displaying all the items of a particular tag, no matter its content type, in the tag detail template.
My guess was to make a Tag with name and slug, then TaggedItem with ctype/object_id/content_object. Blog post gets a many-to-many with Tag, and a signal to save a new TaggedItem. Maybe TaggedItem should've gotten a slug? and maybe Post should've gotten a generic relation instead of a many to many? My query guess is in tags/views.py under context['tagged_items']. That's where I'm stuck now.
# blog/models.py:
from django.db import models
from django.core.urlresolvers import reverse
from django.utils import timezone
class Post(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField()
body = models.TextField()
tags = models.ManyToManyField('tags.Tag', blank=True)
published = models.DateTimeField(default=timezone.now)
class Meta:
ordering = ['-published']
def __unicode__(self):
return u'%s' % self.title
def get_absolute_url(self):
return reverse('blog.views.post_detail', args=[str(self.slug)])
# tags/models.py:
from django.db import models
from django.core.urlresolvers import reverse
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.db.models.signals import post_save
from blog.models import Post
class Tag(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField()
def __unicode__(self):
return u'%s' % self.title
def get_absolute_url(self):
return reverse('tags.views.tag_detail', args=[str(self.slug)])
class TaggedItem(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
def create_tagged_item(sender, **kwargs):
if 'created' in kwargs:
if kwargs['created']:
instance = kwargs['instance']
if instance.tags.all:
content_type = ContentType.objects.get_for_model(instance)
object_id = instance.id
tagged_item = TaggedItem.objects.create(content_type=content_type, object_id=object_id)
post_save.connect(create_tagged_item, sender=Post)
# tags/views.py:
from django.views.generic import ListView, DetailView
from django.contrib.contenttypes.models import ContentType
from .models import Tag
from .models import TaggedItem
class TagListView(ListView):
model = Tag
class TagDetailView(DetailView):
model = Tag
def get_context_data(self, **kwargs):
context = super(TagDetailView, self).get_context_data(**kwargs)
context['tagged_items'] = TaggedItem.objects.filter(content_object__tags__in=self.object.slug) # ????
return context
You don't have any kind of relationship between Tag and TaggedItem, which is making things difficult.
It seems to me that the M2M should be between those two models, and not on Post at all. The whole point is that anything can "be" a tagged item, hence the generic relationship, and that item can have multiple tags. With that, you can then do:
tag = Tab.objects.get(slug=my_slug)
tagged_items = TaggedItem.objects.filter(tags=tag)
content_objects = [item.content_object for item in tagged_items]
But actually, if you're going for simplicity I don't know why you don't use exactly the code from the docs, without the separate Tag model at all. You'll end up with many TaggedItems with the same tag slug/name, but that's OK: you can still do
tagged_items = TaggedItem.objects.filter(slug=my_slug)
and get the content_objects as before.
I ended up going with Timo Zimmermann's approach: looping through possible tags on a generic Entry item. http://www.screamingatmyscreen.com/2012/6/django-and-generic-relations/ Admin friendly and no need for a TaggedItem!
class TagDetailView(DetailView):
model = Tag
def get_context_data(self, **kwargs):
context = super(TagDetailView, self).get_context_data(**kwargs)
item_list = []
for item in ActivityItem.objects.all():
if self.object in item.tags:
item_list.append(item)
context['item_list'] = item_list
return context
Thanks to #DanielRoseman and #Ben for weighing in.

grappelli admin show image

I have a new project on django, in which im using Grappelli and filebrowser, and I have extended the User to have a UserProfile related to it, my question is, how can I modify my code to be able to show on the UserProfile information of a user the profile picture uploaded, and also show it on the Users list?
This is my code now, I dont see any image on the admin!
Admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from models import UserProfile
class UserProfileInline(admin.StackedInline):
model = UserProfile
verbose_name_plural = 'User Profile'
list_display = ('city', 'tel', 'description', 'image_thumbnail',)
class MyUserAdmin(UserAdmin):
list_display = ('username','email','first_name','last_name','date_joined',
'last_login','is_staff', 'is_active',)
inlines = [ UserProfileInline ]
admin.site.unregister(User)
admin.site.register(User, MyUserAdmin)
Models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.utils.translation import ugettext_lazy as _
from apps.common.utils.abstract_models import BaseModel
from apps.common.utils.model_utils import unique_slugify
from filebrowser.base import FileObject
from django.conf import settings
class UserProfile(BaseModel):
user = models.OneToOneField(User, related_name="profile")
city = models.CharField(_("City"), max_length=200)
tel = models.CharField(_("Phone Number"), max_length=50,
help_text=_("(Area Code) (Your phone number)"))
description = models.TextField(null=True, blank=True,
help_text = _("Small description about yourself."))
photo = models.ImageField(max_length=255, upload_to="profiles/",
null=True, blank=True, default="img/default_profile_image.png")
def image_thumbnail(self):
if self.photo:
return u'<img src="%s" width="80" height="80" />' % self.photo.version(ADMIN_THUMBNAIL).url
return u'<img src="/site_media/%s" width="80" height="80" />' % settings.DEFAULT_PROFILE_IMAGE
image_thumbnail.allow_tags = True
def __unicode__(self):
if self.user.first_name or self.user.last_name:
return "%s %s" % (self.user.first_name, self.user.last_name)
else:
return self.user.username
Well I got it, first I wanted to show the image chosen on the UserProfile inline section of the user model for the admin and also on the change list of the admin so heres what I
I changed the models.ImageField to sorl ImageField on the model.py of User profile like this
from sorl.thumbnail import ImageField
class UserProfile(BaseModel):
[...]
photo = ImageField(max_length=255, upload_to="profiles/",
null=True, blank=True, default="img/default_profile_image.png")
Then on the admin all I had to do was add sorl's AdminImageMixin on the UserProfileInline class, like this:
from sorl.thumbnail.admin import AdminImageMixin
class UserProfileInline(AdminImageMixin, admin.StackedInline):
model = UserProfile
verbose_name_plural = 'User Profile'
And that way you get an image on the UserProfile Inline section on the admin for that user, now for the change_list.
For the change list I had to do a small callable function inside the admin.py file on the UserAdmin class, heres what I did, using sorl's get_thumbnail:
from sorl.thumbnail import get_thumbnail
class MyUserAdmin(UserAdmin):
def image_thumbnail(self, obj):
im = get_thumbnail(obj.get_profile().photo, '80x80', quality=99)
return u"<img src='/site_media/%s' />" % im
image_thumbnail.allow_tags = True
list_display = ('image_thumbnail', 'username','email','first_name','last_name','date_joined',
'last_login','is_staff', 'is_active',)
And now I have a change list image of the user profile and also on the UserProfile Inline section.
Hope this works for everyone out there... and thanks #pastylegs for your previous answer!
list_display needs to be a callable:
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display
so you can do:
class UserProfileInline(admin.StackedInline):
def image_thumbnail(self, obj):
return obj.image_thumbnail()
image_thumbnail.short_description = 'Thumbnail'
model = UserProfile
verbose_name_plural = 'User Profile'
list_display = ('city', 'tel', 'description', 'image_thumbnail',)