Prepopulate a Form Field Using Slugs and Integers - Django

Documented by kbruder tech✞ᵀᵀᴹ on Apr 11, 2021
Last updated on Jun 06, 2021


Screenshot_from_2021-04-10_18-33-25

Introduction

Filling out forms online sucks balls. ANYTHING that will reduce the soul sucking task of filling out an online form is welcome. Many times a page with a link to a form will exist with some semblance of context. If the context is enough to know exactly what a field's value is then you can set it behind the scenes without any user action.


  1. What is Meant by "Slug" and "Integer"?

    The way the Django framework handles URLs is very handy and friendly to search engine optimization. In case you are unfamiliar, you can insert dynamically created URLS into HTML pages and pass keyword arguments to the "path()" items in an app's "urls.py" file. For our purposes, we will focus on two argument types; "slug" and "integer".

  2. Slug

    A slug is a word, phrase, title or combination of alpha-numeric characters without spaces, that is compatible with the URL syntax. Only word characters are allowed. A word character in character encoding is any uppercase or lowercase letter, the integers 0 through 9, "_" (underscore) and "-" (hyphen). Slugs are used after the fully qualified domain name and demarcated by "/" (forward slash).

    objects/utils.py
    class Text:
        '''
        def slugify_unique(model, title):
            '''
            Given a DB model and a title, return a unique slug that is unique \
            to all other slug fields of the given DB model.
            
            Arguments
            model - Must be a Django database model that has \
                       a slug field called "slug".
            title - The string used to create the slug.
    
            Returns - A slug that is unique across all instances of the model.
            '''
            from django.utils.text import slugify
            slug = slugify(title)
            existing_slugs = []
            try:
                [existing_slugs.append(str(i.slug)) for i in model.objects.all()]
            except:
                print("There was no slug field found for {}".format(model))
                return slug
            if slug in existing_slugs:
                date_slug = slug + "-" + timezone.now().strftime("%Y%m%d")
                if date_slug in existing_slugs:
                    long_slug = date_slug + timezone.now().strftime("%m%s")
                    return long_slug
                else:
                    return date_slug
            else:
                return slug
    

    Django comes with its own slugify() method which is useful for creating slugs out of other fields from a model instance. The Lookaway CMS version creates a unique slug based on the title field of a model. It checks all other instances of a model to see if the normal slugify routine will produce a unique slug. That way, you can allow the reuse of titles.
    Source: kbruder Tech

    lookaway.info/foo/bar/lorem-ipsum-dolor-20210410/
    

    In this example, "lookaway.info/zine/information/" is a dynamic URL set in "urls.py" that uses the model's 'slug' field to generate the slug "prepopulate-a-form-field-using-slugs".

  3. Integer

    The integer keyword argument is exactly what is sounds like. It's simply a positive whole number or zero.

    lookaway.info/foo/modify/bar/2134859
    

    In this example, the URL "lookaway.info/multimedia/modify/image/" is a dynamic URL that appends the primary key of the instance. The primary key is the 'integer' key word argument.
    Source: kbruder Tech

  4. Assign the Form Field in form_valid() in a CreateView

    foo/views.py
    class BarCreateView(LoginRequiredMixin, CreateView):
        model = Bar
        form_class = BarForm
        ...
        def form_valid(self, form):
            member = self.request.user
            if self.kwargs['model'] == 'baz':
                form.instance.baz = Baz.objects.get(pk=self.kwargs['pk'])
            if self.kwargs['quz']:
                form.instance.quz = self.kwargs['quz']
            form.instance.creation_date = timezone.now()
            form.instance.owner = member
            form.instance.slug = Text.slugify_unique(self.model, form.instance.title)
            return super().form_valid(form)
        ...
    

    In this example, the URL in the template has sent 3 kwargs; 'model', 'pk', and 'baz'. 'model' is a slug that determines which model to use. 'pk' is the primary key of the instance. 'quz' is a boolean (True or False). The 'baz' field on the Bar model is a foreign key field that expects a sing model instance. The model instance and boolean are set after the form is submitted and before the instance is committed to the database.
    Source: kbruder Tech

  5. Add the URL Path to "urls.py"

    foo/urls.py
    ...
    app_name= "foo"
    
    urlpatterns = [
        ...
        path(
            'add/bar/<slug:model>-<int:pk>-<slug:quz>', 
            views.BarCreateView.as_view(),
            name='bar_create',
        ),
        ...
    ]
    

    Source: kbruder Tech

  6. Add the Link to a Template

    foo/templates/foo/bar_detail.html
    <a href="{% url 'foo:bar_create' model='baz' pk=baz.pk quz=baz.quz %}"><button type="button" class="btn btn-sm btn-primary float-right">+Bar</button></a>
    

    Source: kbruder Tech

  7. The Resulting URL

    This URL will open a form. If the form post is valid, then the resulting Bar instance will have a 'baz' field that points to a Baz instance with a PK of 420 and a 'quz' field set to True.

    lookaway.info/foo/add/bar/baz-420-True
    

bitcoin:3MnhNRKgrpTFQWstYicjF6GebY7u7dap4u
Bitcoin Accepted Here

3MnhNRKgrpTFQWstYicjF6GebY7u7dap4u

Please donate some Bitcoin to our site. We can use it to keep improving the site and open up to more members. Any amount will help. Thank you.


litecoin:MT61gm6pdp9rJoLyMWW5A1hnUpxAERnxqg
Litecoin Accepted Here

MT61gm6pdp9rJoLyMWW5A1hnUpxAERnxqg

Please donate some Lite to our site. We can use it to keep improving the site and open it up to more members. Any amount will help. Thank you.