justinmayer / django-autoslug

AutoSlugField for Django. Supports (but not does not require) unidecode/pytils for transliteration. Old issue tracker is at Bitbucket: https://bitbucket.org/neithere/django-autoslug/issues

Home Page:https://readthedocs.org/projects/django-autoslug/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

AutoSlugField with two charfields

Allan-Nava opened this issue · comments

Hi,

is possible to crate a slug with two foreignkey? For example

class Match(models.Model):
    home = models.ForeignKey(
        'groups_manager.Group',
        verbose_name=_('Home Team'),
        related_name='home_player_set'
    )
    away = models.ForeignKey(
        'groups_manager.Group',
        verbose_name=_('Away Team'),
        related_name='away_player_set')

   slug = AutoSlugField(populate_from='home + away')

@Allan-Nava yes, just pass to populate_from a callable that returns the value you want to slug.

Hi @fabiocaccamo ,

I have error with lambda:

Migrations for 'allejo':
  bootcamp/allejo/migrations/0016_match_slug.py
    - Add field slug to match
Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python3.5/dist-packages/django/core/management/__init__.py", line 364, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python3.5/dist-packages/django/core/management/__init__.py", line 356, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python3.5/dist-packages/django/core/management/base.py", line 283, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/local/lib/python3.5/dist-packages/django/core/management/base.py", line 330, in execute
    output = self.handle(*args, **options)
  File "/usr/local/lib/python3.5/dist-packages/django/core/management/commands/makemigrations.py", line 193, in handle
    self.write_migration_files(changes)
  File "/usr/local/lib/python3.5/dist-packages/django/core/management/commands/makemigrations.py", line 231, in write_migration_files
    migration_string = writer.as_string()
  File "/usr/local/lib/python3.5/dist-packages/django/db/migrations/writer.py", line 163, in as_string
    operation_string, operation_imports = OperationWriter(operation).serialize()
  File "/usr/local/lib/python3.5/dist-packages/django/db/migrations/writer.py", line 120, in serialize
    _write(arg_name, arg_value)
  File "/usr/local/lib/python3.5/dist-packages/django/db/migrations/writer.py", line 84, in _write
    arg_string, arg_imports = MigrationWriter.serialize(_arg_value)
  File "/usr/local/lib/python3.5/dist-packages/django/db/migrations/writer.py", line 293, in serialize
    return serializer_factory(value).serialize()
  File "/usr/local/lib/python3.5/dist-packages/django/db/migrations/serializer.py", line 229, in serialize
    return self.serialize_deconstructed(path, args, kwargs)
  File "/usr/local/lib/python3.5/dist-packages/django/db/migrations/serializer.py", line 101, in serialize_deconstructed
    arg_string, arg_imports = serializer_factory(arg).serialize()
  File "/usr/local/lib/python3.5/dist-packages/django/db/migrations/serializer.py", line 164, in serialize
    raise ValueError("Cannot serialize function: lambda")
ValueError: Cannot serialize function: lambda

I try with:
slug = AutoSlugField(populate_from='home, away')

in models.py (outside your model class):

def get_populate_from(instance):
    return '%s-%s' % (instance.home, instance.away, )

then in your model:

slug = AutoSlugField(populate_from=get_populate_from)

Hi @fabiocaccamo , i try this:

def get_fullname_match(self):
        from slugify import slugify
        #Cambiato formato della data in d m Y
        d = self.game_date.strftime('%d %m %Y')
        name = "%s %s %s %s" % (self.grade, self.home, self.away, d)
        match = slugify(name, to_lower=True, separator="-")
        return match

this is example, lol is the same XD

# autoslugify value from a dynamic attribute (i.e. a method)
slug = AutoSlugField(populate_from='get_full_name')

In this case populate_from must be a callable, and it will receive an instance arg.
The callable must return a string, and AutoSlugField will convert it to a slug.

Try as I told you.

Now I try with populate_from @fabiocaccamo

@fabiocaccamo Is possibile extend the lenght of autoslug field?

max_length

@fabiocaccamo ok perfect i added!

in models.py (outside your model class):

def get_populate_from(instance):
    return '%s-%s' % (instance.home, instance.away, )

then in your model:

slug = AutoSlugField(populate_from=get_populate_from)

Hi, FYI, today i just needed a more standardized solution, so I propose this solution for those who are interested:

from operator import attrgetter

def get_populate_from(instance):
    attrs = [attr.replace("__", ".") for attr in instance.AUTOSLUG_FIELDS]
    attrs_values = [attrgetter(attr)(instance) for attr in attrs]
    
    return "-".join(attrs_values)

Just add an AUTOSLUG_FIELDS constant with desired values:

class Example(models.Model):
    AUTOSLUG_FIELDS = ("user__name", "title")

    user = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=128)
    
    slug = AutoSlugField(max_length=256, populate_from=get_populate_from, unique=True)

Please add this to documentation. The documentation still says lambda function can be used https://django-autoslug.readthedocs.io/en/latest/

in models.py (outside your model class):

def get_populate_from(instance):
    return '%s-%s' % (instance.home, instance.away, )

then in your model:

slug = AutoSlugField(populate_from=get_populate_from)

Hi, FYI, today i just needed a more standardized solution, so I propose this solution for those who are interested:

from operator import attrgetter

def get_populate_from(instance):
    attrs = [attr.replace("__", ".") for attr in instance.AUTOSLUG_FIELDS]
    attrs_values = [attrgetter(attr)(instance) for attr in attrs]
    
    return "-".join(attrs_values)

Just add an AUTOSLUG_FIELDS constant with desired values:

class Example(models.Model):
    AUTOSLUG_FIELDS = ("user__name", "title")

    user = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=128)
    
    slug = AutoSlugField(max_length=256, populate_from=get_populate_from, unique=True)

but why my slug that contains uppercase not work with this?

@kmarilleau @kwhandy your idea is nice, but I think that it could be implemented better:

from operator import attrgetter

def get_populate_from(fields):
    def wrapped(instance):
        attrs = [attr.replace("__", ".") for attr in fields]
        attrs_values = [attrgetter(attr)(instance) for attr in attrs]
        return "-".join(attrs_values)
    return wrapped
class Example(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=128)
    slug = AutoSlugField(max_length=256, populate_from=get_populate_from("user__name", "title"), unique=True)

Unfortunately, this method yields this error:

TypeError: get_populate_from() takes 1 positional argument but 2 were given