I hope you're well. I've two questions for you:
class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
url_image = models.URLField(max_length=200, default='SOME STRING')
author = models.ForeignKey(User, on_delete= models.CASCADE,related_name='blog_posts')
updated_on = models.DateTimeField(auto_now= True)
name_site = models.CharField(max_length=200, default='NA')
url_site = models.URLField(max_length=200, default='https://exemple.fr/')
content = models.TextField()
I. I want my title (unique=False) because I have some similar titles. So is it possible to save my slug (editable=False) with slugify with something like that:
slug_str = "%s %s" % (self.title, 4 random numbers like that 0476)
If anyone has a better idea, I'm interested in
Thanks a lot :) have a good holidays and take care
Here are a couple functions that I use. You pass in the model instance and the desired title into unique_slugify which will continue trying to add random strings until one is created that doesn't already exist.
import random
import string
def random_string_generator(size=10, chars=string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
def unique_slugify(instance, slug):
model = instance.__class__
unique_slug = slug
while model.objects.filter(slug=unique_slug).exists():
unique_slug = slug
unique_slug += random_string_generator(size=4)
return unique_slug
I usually use it by overriding the model save method.
class YourModel(models.Model):
slug = models.SlugField(max_length=200, unique=True)
title = models.CharField(max_length=200)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = unique_slugify(self, slugify(self.title))
super().save(*args, **kwargs)
in my opinion, it doesn't make sens two posts may have the same title even with two different slugs, it even confuses readers and even worst it's very bad for SEO. i suggest you to avoid this path and try to review the logic
in models.py
class Post(models.Model):
title = models.CharField(_('title'), max_length=200,
unique=True, # title should be unique
help_text=_('The title of the entry.')
)
slug = models.SlugField(_('slug'), max_length=200,
unique=True, null=True, blank=True,
help_text=_(
'If blank, the slug will be generated automatically '
'from the given title.'
)
)
[..]
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title) # here you don't need to add random numbers since the title is already unque
super().save(*args, **kwargs)
in admin.py
class PostAdmin(admin.ModelAdmin):
list_display = ('title', .. )
readonly_fields = ('slug', .. ) # Add slug to read_only fields to make it not editable if you want
Related
I have created a website and want to count user generated posts.
I tried to do it as follows:
models.py
class Blog(models.Model):
user = models.ForeignKey(
User,
related_name='user_blogs',
on_delete=models.CASCADE
)
category = models.ForeignKey(
Category,
related_name='category_blogs',
on_delete=models.CASCADE
)
title = models.CharField(
max_length=250
)
slug = models.SlugField(null=True, blank=True)
banner = models.ImageField(upload_to='blog_banners')
description = RichTextField()
created_date = models.DateField(auto_now_add=True)
def __str__(self) -> str:
return self.title
def save(self, *args, **kwargs):
updating = self.pk is not None
if updating:
self.slug = generate_unique_slug(self, self.title, update=True)
super().save(*args, **kwargs)
else:
self.slug = generate_unique_slug(self, self.title)
super().save(*args, **kwargs)
templates
<span>Posts: <strong>{{account.user_blogs.count}}</strong></span>
but it doesn't work
what is the problem? should I rewrite the code at all?
If you're trying to count posts created by the logged-in user
<span>Posts: <strong>{{ request.user.user_blogs.count }}</strong></span>
I want to make slugs on post save for my model using three fields one charfield and two ManytoMany Fields but getting error during saving.
Here is my code:
Heading ##class product(models.Model):
id = models.AutoField(primary_key=True)
image = models.ForeignKey(all_images, verbose_name='Product Images', on_delete=models.CASCADE, related_name='proimages')
ProductName = models.CharField(max_length=200, null=False,default="None", blank=False,verbose_name="Product Name")
CategoryName = models.ManyToManyField(category,related_name='procat', blank=False,verbose_name="Category Name")
SubcatName = models.ManyToManyField(subcategory,related_name='prosubcat', blank=False,verbose_name="Sub-category Name")
description = RichTextUploadingField(blank= False,verbose_name="Description")
price = models.IntegerField(default=100, null=True, blank=True, verbose_name='Price')
slug = models.SlugField(max_length=55, blank=True, null=True)
def get_slug(self):
slug = self.ProductName
try:
for items in self.SubcatName.all():
slug +=items.name
try:
for items in self.CategoryName.all():
slug +=items.CategoryName
except:
pass
except:
pass
return slugify(slug)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = self.get_slug()
super(product, self).save(*args, **kwargs)
I have two models, not connected by ForeignKey. I would to display them on one page in admin interface, in the way like inlines in Django.
I can't associate PostFile with Post, because uploaded medias should be available to every Post which was and will be created in future. I have no idea what I can do if inlines are unavailable.
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'Draft'),
('published', 'Published')
)
title = models.CharField(max_length=255)
slug = models.SlugField(max_length=255, unique_for_date='publish_date', blank=True)
author = models.ForeignKey(User, related_name='blog_posts', on_delete=models.CASCADE, blank=True)
content = MarkdownxField()
publish_date = models.DateTimeField(default=timezone.now)
creation_date = models.DateTimeField(auto_now_add=True)
last_update_date = models.DateField(auto_now=True)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
tags = models.ManyToManyField(Tag)
objects = models.Manager()
class Meta:
ordering = [
'-publish_date'
]
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('blog:post_detail',
args=[
self.publish_date.strftime('%Y'),
self.publish_date.strftime('%m'),
self.publish_date.strftime('%d'),
self.slug
])
#https://github.com/neutronX/django-markdownx/issues/83
def formatted_markdown(self):
return markdownify(self.content)
class PostFile(models.Model):
file_name = models.CharField(max_length=200, blank=True)
file_object = models.FileField(upload_to='post_files/')
file_upload_date = models.DateTimeField(auto_now_add=True)
def save(self, *args, **kwargs):
if not self.file_name:
self.file_name = self.file_object.name
super(PostFile, self).save(*args, **kwargs)
def file_url(self):
return self.file_object.url
def __str__(self):
return self.file_name
I would to receive in output a Post model admin page, where on the bottom I have listed all PostFile objects. This will give me easy and fast acces to PostFile-object url on media folder. I don't want each time to open new tab, and to go to PostFile model admin page to check url of object.
I am working with slug on my model. Although, the entries for slug are not unique. When I try to go to a url containing slug, it says get() returned more than one object and I understand that it is because the entries are not unique. How am I supposed to change the slug a bit, if identical entries occur?
model
class Cabin(models.Model):
centre_name = models.ForeignKey(Centre, on_delete=models.CASCADE )
code = models.CharField(max_length=8, unique=True, default=unique_rand)
total_seats = models.IntegerField(blank='False')
category=models.CharField(max_length=100, default=False)
booked_date=models.DateField(blank='False')
released_date=models.DateField(blank='False')
price=models.IntegerField(blank=False, default=None)
slug = models.SlugField(unique=False,default=None,blank=True)
objects = UserManager()
def save(self, *args, **kwargs):
self.slug = slugify(self.category)
super(Client, self).save(*args, **kwargs)
First of all it might be better to set unique=True, such that this can never happen, furthermore you can :
class Cabin(models.Model):
centre_name = models.ForeignKey(Centre, on_delete=models.CASCADE )
code = models.CharField(max_length=8, unique=True, default=unique_rand)
total_seats = models.IntegerField(blank='False')
category=models.CharField(max_length=100, default=False)
booked_date=models.DateField(blank='False')
released_date=models.DateField(blank='False')
price=models.IntegerField(blank=False, default=None)
slug = models.SlugField(unique=True,default=None,blank=True)
objects = UserManager()
def save(self, *args, **kwargs):
slug = originalslug = slugify(self.category)
i = 0
while Cabin.objects.exist(slug=slug):
slug = '{}{}'.format(originalslug, i)
i += 1
self.slug = slug
super(Client, self).save(*args, **kwargs)
We here thus increment i until we found a slug that is not yet used.
Note that there exists an AutoSlugField in the django-extensions package [PyPi], that automates this slug procedure. For example:
from django.db import models
from django_extensions.db.fields import AutoSlugField
class Cabin(models.Model):
centre_name = models.ForeignKey(Centre, on_delete=models.CASCADE )
code = models.CharField(max_length=8, unique=True, default=unique_rand)
total_seats = models.IntegerField(blank='False')
category=models.CharField(max_length=100, default=False)
booked_date=models.DateField(blank='False')
released_date=models.DateField(blank='False')
price=models.IntegerField(blank=False, default=None)
slug = AutoSlugField(populate_from='category')
objects = UserManager()
In my django project there's a Blog model which I'm willing to create a slug for it's title:
class Blog(models.Model):
title = models.CharField(default='', max_length=100, verbose_name=u'عنوان')
slug = models.SlugField(max_length=100, allow_unicode=True)
# other stuffs
def save(self, *args, **kwargs):
self.slug = slugify(self.title, allow_unicode=True)
super(Blog, self).save(*args, **kwargs)
def __str__(self):
return self.slug
In django admin I don't fill slug field and when I hit the save button it says:
This field is required.
Isn't my code suppose to create slug automatically? Is there something else I should do?
You should set blank=True for your slug field. This way it won't be required and it will be set to slugified title when save method will run.
class Blog(models.Model):
title = models.CharField(default='', max_length=100, verbose_name=u'عنوان')
slug = models.SlugField(max_length=100, allow_unicode=True, blank=True)