type - Cómo crear un slug único en Django
type models django (7)
Django proporciona un campo de modelo SlugField para que esto sea más fácil para usted. Aquí hay un ejemplo de ello en una aplicación de "blog".
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField(blank=True)
slug = models.SlugField(unique=True)
@models.permalink
def get_absolute_url(self):
return ''blog:post'', (self.slug,)
Tenga en cuenta que hemos establecido unique = True para nuestro campo de slug: en este proyecto buscaremos publicaciones por su slug, por lo que debemos asegurarnos de que sean únicos. Esto es lo que podría ver el view.py de nuestra aplicación para hacer esto:
from .models import Post
def post(request, slug):
post = get_object_or_404(Post, slug=slug)
return render(request, ''blog/post.html'', {
''post'': post,
})
Estoy intentando crear un slug único en Django para poder acceder a una publicación a través de una URL como esta: http://www.example.com/buy-a-new-bike_Boston-MA-02111_2
Los modelos relevantes:
class ZipCode(models.Model):
zipcode = models.CharField(max_length=5)
city = models.CharField(max_length=64)
statecode = models.CharField(max_length=32)
class Need(models.Model):
title = models.CharField(max_length=50)
us_zip = models.CharField(max_length=5)
slug = ?????
def get_city():
zip = ZipCode.objects.get(zipcode=self.us_zip)
city = "%s, %s %s" % (zip.city, zip.statecode, zip.zipcode)
return city
Un ejemplo de registro ZipCode:
- zipcode = "02111"
- city = "Boston"
- statecode = "MA"
Un registro de necesidad de muestra:
- title = "comprar una bicicleta nueva"
- us_zip = "02111"
- slug = "buy-a-new-bike_Boston-MA-02111_2" (deseado)
¿Algún consejo sobre cómo crear esta babosa única? Su composición es:
- Need.title + "_" + Need.get_city () + "_" + un entero incremental opcional para hacerlo único. Todos los espacios deben ser reemplazados con "-".
NOTA: Mi barra deseada anterior asume que la barra "buy-a-new-bike_Boston-MA-02111" ya existe, que es lo que tiene el "_2" añadido para hacerlo único.
He intentado django-extensions, pero parece que solo puede tomar un campo o una tupla de campos para construir el slug único. Necesito pasar la función get_city () así como el conector "_" entre el título y la ciudad. ¿Alguien resolvió esto y está dispuesto a compartir?
¡Gracias!
ACTUALIZAR
Ya estoy usando django-extensions para su UUIDField, por lo que sería bueno si también pudiera usarse para su AutoSlugField.
Esta es una implementación simple que genera el slug desde el título, no depende de otros fragmentos de código:
from django.template.defaultfilters import slugify
class Article(models.Model):
...
def save(self, **kwargs):
if not self.slug:
slug = slugify(self.title)
while True:
try:
article = Article.objects.get(slug=slug)
if article == self:
self.slug = slug
break
else:
slug = slug + ''-''
except:
self.slug = slug
break
super(Article, self).save()
Hola puedes probar esta función
class Training(models.Model):
title = models.CharField(max_length=250)
text = models.TextField()
created_date = models.DateTimeField(
auto_now_add=True, editable=False, )
slug = models.SlugField(unique=True, editable=False, max_length=250)
def __unicode__(self):
return self.title
def save(self, *args, **kwargs):
self.slug =get_unique_slug(self.id,self.title,Training.objects)
return super(Training, self).save(*args, **kwargs)
def get_unique_slug(id,title,obj):
slug = slugify(title.replace(''ı'', ''i''))
unique_slug = slug
counter = 1
while obj.filter(slug=unique_slug).exists():
if(obj.filter(slug=unique_slug).values(''id'')[0][''id'']==id):
break
unique_slug = ''{}-{}''.format(slug, counter)
counter += 1
return unique_slug
Mi pequeño código:
def save(self, *args, **kwargs):
strtime = "".join(str(time()).split("."))
string = "%s-%s" % (strtime[7:], self.title)
self.slug = slugify(string)
super(Need, self).save()
Si está pensando en utilizar una aplicación para que lo haga por usted, aquí tiene una.
https://github.com/un33k/django-uuslug
UUSlug = (``U``nique + ``U``code Slug)
Unicode Test Example
=====================
from uuslug import uuslug as slugify
s = "This is a test ---"
r = slugify(s)
self.assertEquals(r, "this-is-a-test")
s = ''C/'est déjà l/'été.''
r = slugify(s)
self.assertEquals(r, "c-est-deja-l-ete")
s = ''Nín hǎo. Wǒ shì zhōng guó rén''
r = slugify(s)
self.assertEquals(r, "nin-hao-wo-shi-zhong-guo-ren")
s = ''影師嗎''
r = slugify(s)
self.assertEquals(r, "ying-shi-ma")
Uniqueness Test Example
=======================
Override your objects save method with something like this (models.py)
from django.db import models
from uuslug import uuslug as slugify
class CoolSlug(models.Model):
name = models.CharField(max_length=100)
slug = models.CharField(max_length=200)
def __unicode__(self):
return self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name, instance=self)
super(CoolSlug, self).save(*args, **kwargs)
Test:
=====
name = "john"
c = CoolSlug.objects.create(name=name)
c.save()
self.assertEquals(c.slug, name) # slug = "john"
c1 = CoolSlug.objects.create(name=name)
c1.save()
self.assertEquals(c1.slug, name+"-1") # slug = "john-1"
Uso este snippet para generar un slug único y mi método de guardado típico se ve a continuación
slug será Django SlugField con blank = True pero impondrá slug en el método de guardar.
El método típico de guardado para el modelo de Need podría verse abajo.
def save(self, **kwargs):
slug_str = "%s %s" % (self.title, self.us_zip)
unique_slugify(self, slug_str)
super(Need, self).save(**kwargs)
y esto generará una babosa como buy-a-new-bike_Boston-MA-02111, buy-a-new-bike_Boston-MA-02111-1 y así sucesivamente. La salida puede ser un poco diferente, pero siempre puede revisar los fragmentos y personalizarlos según sus necesidades.
class Need(models.Model):
title = models.CharField(max_length=50)
us_zip = models.CharField(max_length=5)
slug = models.SlugField(unique=True)
def save(self, **kwargs):
slug_str = "%s %s" % (self.title, self.us_zip)
super(Need, self).save()