Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django custom field with 2 fields

I found a markdown editor that I'm adapting to make it work well with Django. I would like to have a field to store the raw markdown and one for the compiled HTML for optimization purposes. I want to create a custom field and widget to hide the complexity and make it reusable everywhere on my website. In this custom field, I would like to have two textfields but I didn't find if it was possible. My other solutions are :

  • to have a model with those two fields and my custom field is actually a foreign key to this model. I like this one because doing some migration for everything is really easy, maybe the implementation will be somewhat tricky.
  • to create a abstract model with those two fields. I override the save method to fill the html entry
like image 714
Dorian Amouroux Avatar asked Sep 14 '25 18:09

Dorian Amouroux


1 Answers

Use the right tool for the job(tm).

  • Use a custom field to handle one python object to be stored in one field. The goal here is translate from storage format to functional object and vice versa. It's possible to use multiple fields, but tricky. See the ImageField as an example.

  • Use inheritance to augment models with one or more fields, methods, what you want. The goal here is to be able to reuse code.

    class CompilableMarkdownBase(models.Model):
        markdown = models.TextField(default='[//]: # (Start Markdown here)')
        compiled_html = models.TextField(editable=False, null=True)
    
        def clean(self):
            if self.markdown != models.NOT_PROVIDED:
                self.compiled_html = compile_html(self.markdown)
    
        class Meta:
            abstract = True
    

We do this in clean(), not save, as it's made for it: altering submitted form data or database storage based on other fields. Since python supports multiple inheritance, you can tack it on any model. Using Mezzanine as an example:

class ProductPage(Page, CompilableMarkdownBase):
    pass

Just be aware of field name clashes, which you can check with ./manage.py check.