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",)}
Related
i have model like this
### models.py
class Pizza(models.Model):
name = models.CharField()
price = models.IntegerField()
have_recipe = models.BooleanField()
### admin.py
admin.register(Pizza)
class PizzaAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'price')
exclude = ('have_recipe',)
when I enter localhost:8000/admin/pizza i can see all of pizza objects,
but, I want to make admin pizza list show only have_recipe=True objects and nobody can't control this filter in admin page
is there any solution??
You can override the get_queryset(…) method [Django-doc] and work with:
# admin.py
#admin.register(Pizza)
class PizzaAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'price')
exclude = ('have_recipe',)
def get_queryset(self, *args, **kwargs):
return super().get_queryset(*args, **kwargs).filter(
have_recipe=True
)
You should also use #admin.register(Pizza) as a decorator, so with a leading #.
I have a simple blog where the post model contains a slug field that is prefilled with the post title. I would like to know how to get this slug updated in the background when the user updates a post title in the viewUpdate:
models.py
class Post(models.Model):
title = models.CharField(max_length=150)
content = models.TextField()
date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(
CustomUser,
on_delete=models.CASCADE
)
slug = models.SlugField(unique=True)
def get_absolute_url(self):
return reverse('post_detail', kwargs={'slug': self.slug})
def save(self, *args, **kwargs):
self.slug = self.slug or slugify(self.title)
super().save(*args, **kwargs)
urls.py
urlpatterns = [
path('post/<slug:slug>/', views.PostDetailView.as_view(), name='post_detail'),
]
views.py
class PostUpdateView(UpdateView):
model = Post
fields = ['title', 'content', 'tags']
I assume I should add something else to view.py in order to have the slug updated but after hours googling it, I could not find it.
Please let me know if you need more information. It is quite a simple question so I am not sure if I should provide anything else.
You can change the savemethod to:
class Post(models.Model):
# …
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super().save(*args, **kwargs)
That being said, it is not per se a good idea to change the slug. A slug is usually used in a URL. That thus means that if a URL for a Post is for example bookmarked by a user, and later the title changes, then that URL will no longer work. Terefore a slug is usually something that should not be modified (often). In fact in most content management systems (CMS), the slug does not change, and you can look at the URL to see the original title of the article.
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.
How do I limit the values returned via the ManyToMany relationship and thus displayed in the <SELECT> field on my form to only show the spots which were created by the currently logged in user?
models.py
class Project(models.Model):
owner = models.ForeignKey(User, editable=False)
...
spots = models.ManyToManyField(to='Spot', blank=True, )
class Spot(models.Model):
owner = models.ForeignKey(User, editable=False)
spot_name = models.CharField(max_length=80, blank=False)
forms.py
from django import forms
from .models import Project, Spot
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
exclude = ('owner', )
class SpotForm(forms.ModelForm):
class Meta:
model = Spot
exclude = ('owner', )
I'm using GenericViews for Update and Create and currently see all of the entries everyone has made into Spots when I'm updating or creating a Project. I want to see only the entries entered by the logged in user. For completeness sake, yes, the project.owner and spot.owner were set to User when they were created.
I've tried def INIT in the forms.py and using limit_choices_to on the manytomany field in the model. Either I did those both wrong or that's not the right way to do it.
thank you!
in your forms.py
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
exclude = ('owner', )
def __init__(self, user_id, *args, **kwargs):
self.fields['spots'] = forms.ModelChoiceField(widget=forms.Select, queryset=Project.objects.filter(owner=user_id))
class SpotForm(forms.ModelForm):
class Meta:
model = Spot
exclude = ('owner', )
def __init__(self, user_id, *args, **kwargs):
self.fields['spot_name'] = forms.ModelChoiceField(widget=forms.Select, queryset=Spot.objects.filter(owner=user_id))
in your views.py
user_id = Project.objects.get(owner=request.user).owner
project_form = ProjectForm(user_id)
spot_form = SpotForm(user_id)
As I mentioned above, Dean's answer was really close, but didn't work for me. Primarily because request is not accessible in the view directly. Maybe it is in older Django versions? I'm on 1.9. Thank you Dean, you got me over the hump!
The gist of what's going on is adding User into the kwargs in the View, passing that to the ModelForm, remove User from the kwargs and use it to filter the Spots before the form is shown.
This is the code that worked for my project:
views.py
class ProjectUpdate(UpdateView):
model = Project
success_url = reverse_lazy('projects-mine')
form_class = ProjectForm
def dispatch(self, *args, **kwargs):
return super(ProjectUpdate, self).dispatch(*args, **kwargs)
def get_form_kwargs(self):
kwargs = super(ProjectUpdate, self).get_form_kwargs()
kwargs.update({'user': self.request.user})
return kwargs
forms.py
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
exclude = ('owner', 'whispir_id')
def __init__(self, *args, **kwargs):
user_id = kwargs.pop('user')
super(ProjectForm, self).__init__(*args, **kwargs)
self.fields['spots'] = forms.ModelMultipleChoiceField(queryset=Spot.objects.filter(owner=user_id))
class SpotForm(forms.ModelForm):
class Meta:
model = Spot
exclude = ('owner', )
def __init__(self, *args, **kwargs):
user_id = kwargs.pop('user')
super(SpotForm, self).__init__(*args, **kwargs)
self.fields['spot_name'] = forms.ModelMultipleChoiceField(queryset=Spot.objects.filter(owner=user_id))
I have a simple tag model and a simple project model.
In the project model I have a m2m to the tag model.
I want to return all the projects with a tag. I'm almost there.
Right now the view below returns invalid literal for int() with base 10: 'cheap'
So, it has the right slug, and it's making the query, but it's trying to get the list of projects based on the id of the m2m tag.
Any suggestion much appreciated.
My Tag Model:
class Tag(models.Model):
"""
A basic tag model for projects
"""
name = models.CharField(max_length=100, unique=True)
slug = models.CharField(max_length=100)
description = models.TextField(blank=True)
class Meta:
ordering = ('name',)
verbose_name = _('Tag')
verbose_name_plural = _('Tags')
def __unicode__(self):
return self.name
#models.permalink
def get_url_path(self):
return ('TagDetail', (), {'slug': self.slug})
My url:
# tags/<slug>/ The detail view for an archived project
url(regex=r'^tags/(?P<slug>[\w-]+)/$',
view=TagDetail.as_view(),
name='tag_detail',
),
My view I'm trying to figure out:
class TagDetail(ListView):
""" Get all projects for a tag """
template_name = "projects/TagDetail.html"
def get_queryset(self):
tags = get_list_or_404(Project, tags=self.kwargs['slug'], displayed=True)
paginate_by = 10
#method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(TagDetail, self).dispatch(*args, **kwargs)
Assuming your Project model looks like this
class Project( models.Model ):
tags=models.ManyToManyField( Tag )
match to the tag's slug
def get_queryset( self ):
return get_list_or_404(Project, tags__slug=self.kwargs['slug'], displayed=True)
the only change being tags__slug.