Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django model field default based on another model field

I use Django Admin to build a management site. There are two tables, one is ModelA with data in it, another is ModelB with nothing in it. If one model field b_b in ModelB is None, it can be displayed on the webpage with the value of ModelA's field a_b.

I don't know how to do it, Here is the pseudo code:

In models.py

from django.db import models

class ModelA(models.Model):
  a_a = models.CharField(max_length=6)
  a_b = models.CharField(max_length=6)

class ModelB(models.Model):
  modela = models.OneToOneField(ModelA)
  b_b = models.CharField(max_length=6, choices=[(1, 'M'), (2, 'F')], default=self.modela.a_b)

In admin.py

from django.contrib import admin
from .models import ModelA, ModelB

class ModelBAdmin(admin.ModelAdmin):
  fields = ['b_b']
  list_display = ('b_b')

I think if b_b of modelB have default value of relative a_b value of modelA, I have a default value of b_b(View) in the django admin change(edit) page which associate data to a particular modelB instance.

I want to fill b_b in web page more easily.

I don't know whether this requirement can be achieved? Or there is another way can achieve this?

I try to custom the templates filter as following:

In templates/admin/includes/fieldset.html

 {% load drop_null %}

    {% if field.is_checkbox %}
        {{ field.field }}{{ field.label_tag }}
    {% else %}
        {{ field.label_tag }}
        {% if field.is_readonly %}
            <p>{{ field.contents }}</p>
        {% else %}
            {% if field.field.name == 'b_b' %}
                {{ field|dropnull }}
            {% else %}
                {{ field.field }}
            {% endif %}
        {% endif %}
    {% endif %}

In templatetags/drop_null.py

from django import template
register = template.Library()

@register.filter(name='dropnull')
def dropnull(cls):
    return cls.modela.a_b

The 'field' is < django.contrib.admin.helpers.AdminField object at 0x3cc3550> . It is not an instance of ModelB. How can I get ModelB instance?

like image 240
Jameson Avatar asked Jul 08 '15 12:07

Jameson


1 Answers

You can override the save method of your modelB model instead of providing a default value:

class ModelB(models.Model):
    modela = models.OneToOneField(ModelA)
    b_b = models.CharField(max_length=6, choices=[(1, 'M'), (2, 'F')], blank=True)

    def save(self, *args, **kwargs):
        if not self.b_b:
            self.b_b = self.modela.a_b
        super(ModelB, self).save(*args, **kwargs)

Edit after clarification in the comments

If you just want to display the value to visitors but want to keep the fact that the ModelB.b_b is empty, the logic should lay in the template.

Assuming your view set objB in the context being the ModelB object your are interested to display, the relevant part of the template should look like:

{% with objB.b_b as bValue %}
{% if not bValue %}
    <p>{{ objB.modela.a_b }}</p>
{% else %}
    <p>{{ bValue }}</p>
{% endif %}
{% endwith %}
like image 112
301_Moved_Permanently Avatar answered Oct 13 '22 15:10

301_Moved_Permanently