I have two Django models related by a ManyToManyField relationship. Everything works fine except for the inline add dropdown which lists ugly automatically created object names instead of allowing me to format it. How can I specify that?
Models:
class Job(models.Model):
type = models.CharField(max_length=32, choices=JobChoices)
guid = models.CharField(max_length=32)
title = models.CharField(max_length=256)
started_time = models.DateTimeField()
ended_time = models.DateTimeField(blank=True, null=True)
enabled = models.BooleanField(default=False)
running = models.BooleanField(default=False)
working_job_status = models.CharField(max_length=32, choices=StatusCoices)
working_job_length = models.IntegerField(blank=True, null=True)
working_job_progress = models.IntegerField(blank=True, null=True)
working_job_eta_sec = models.IntegerField(blank=True, null=True)
RepeatUnit = (
('s', 'Second'),
('m', 'Minute'),
('h', 'Hour'),
('d', 'Day'),
('W', 'Week'),
('M', 'Month'),
('Y', 'Year'),
)
class Schedule(models.Model):
title = models.CharField(max_length=128)
job = models.ManyToManyField(Job, blank=True, null=True)
start_time = models.DateTimeField(null=False)
end_time = models.DateTimeField(blank=True, null=True)
repeat_unit = models.CharField(blank=True, null=True, max_length=1, choices=RepeatUnit)
repeat_every = models.IntegerField(blank=True, null=True)
repeat_max_count = models.IntegerField(blank=True, null=True)
def __unicode__(self):
return f'{self.title}'
Admin:
class ScheduleAdmin(admin.ModelAdmin):
list_display = ['id', 'title', 'start_time', 'end_time', 'repeat_unit', 'repeat_every', 'repeat_max_count']
class ScheduleInline(admin.TabularInline):
model = Schedule.job.through
min_num = 0
extra = 0
# fields = ('title', )
verbose_name = "Schedule"
verbose_name_plural = "Schedules"
class JobAdmin(admin.ModelAdmin):
list_display = ['id', 'type', 'guid', 'title', 'started_time', 'ended_time', 'enabled', 'running', 'progress']
inlines = [ScheduleInline,]
admin.site.register(Schedule, ScheduleAdmin)
admin.site.register(Job, JobAdmin)
And, when I click on the inlines drop-down menu I get:
changing from __unicode__(self) to __str__(self) did the trick
Related
I have the following constellation of Tables, which are linked via FK's:
(omitted a few fields for better readability)
class ProductDetail(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
product_detail = models.CharField(max_length=100, primary_key=True, verbose_name='Product Detail Name')
materialcode = models.CharField(max_length=20, blank=False, null=False, verbose_name='Material-Code')
billing_model = models.ForeignKey(BillingModel, on_delete=models.CASCADE)
....
--------------
class MinimumRevenue(models.Model):
operator = models.ForeignKey(Operator, on_delete=models.CASCADE)
billing_model = models.ForeignKey(BillingModel, on_delete=models.CASCADE)
minimum_revenue = models.DecimalField(decimal_places=2, max_digits=20, verbose_name='Minimum Revenue')
currency = models.ForeignKey(Currency, on_delete=models.CASCADE)
product_detail = models.ForeignKey(ProductDetail, on_delete=models.CASCADE, verbose_name='Product Detail')
event_type_assignment = models.CharField(max_length=100, verbose_name='Event Type Assignment')
start_date = models.DateField(blank=False, null=False, verbose_name='Start Date', default=get_first_of_month)
end_date = models.DateField(blank=False, null=False, verbose_name='End Date')
....
And a Table (Django_Tables2) which points to the MinimumRevenue Model (which works as designed), now I would like to also show some more related fields in my Table:
class MinimumRevenueTable(tables.Table):
edit = tables.LinkColumn('non_voice:minimum_revenue_update', orderable=False, text='Edit', args=[A('pk')])
invoice_text = tables.TemplateColumn(
'<data-toggle="tooltip" title="{{record.context}}">{{record.invoice_text|truncatewords:2}}')
start_date = tables.DateColumn(format='Y-m-d')
end_date = tables.DateColumn(format='Y-m-d')
foreigncolumn = tables.Column(accessor='productdetail.materialcode')
class Meta:
model = MinimumRevenue
template_name = "django_tables2/bootstrap4.html"
fields = ('operator', 'billing_model', 'minimum_revenue', 'product', 'product_detail', 'event_type_assignment',
'start_date', 'end_date', 'invoice_text', 'currency', 'foreigncolumn')
attrs = {'class': 'table table-hover', }
The foreigncolumn column is never filled, just showing '-', I also tried it with other columns of ProductDetail, but never get any result, would really appreciate any solutions!
I try to serialize query set
def do(self):
reservations = Reservation.objects.all()
serializer = ReservationSerializer(data=reservations, many=True)
if serializer.is_valid():
encoded_data = json.dumps(serializer.data)
r = requests.post('http://httpbin.org/post', headers={'Content-Type': 'application/json'}, data=encoded_data)
print(r.text)
else:
print(serializer.errors)
And I always get error of
{u'non_field_errors': [u'Expected a list of items but got type "QuerySet".']}
I tried to use values() on query set, and then convert to list, but this way I get objects without nested models
model
class Reservation(models.Model):
start = models.DateField(verbose_name='Заезд', auto_now=False, auto_now_add=False, blank=False)
end = models.DateField(verbose_name='Выезд', auto_now=False, auto_now_add=False, blank=False)
check_in_time = models.TimeField(verbose_name='Время заезда', blank=False)
check_out_time = models.TimeField(verbose_name='Время выезда', blank=False)
has_refund = models.BooleanField(verbose_name='Возвратная бронь', default=True)
payed = models.BooleanField(verbose_name='Оплачено', default=False)
reserved_days = models.ManyToManyField(Day, blank=False)
additional_services = models.ManyToManyField(AdditionalService)
guest_name = models.CharField(verbose_name='Имя гостя', max_length=200, blank=True)
reservation_number = models.CharField(verbose_name='Номер брони', max_length=200, blank=True)
class AdditionalService(models.Model):
payment_date = models.CharField(verbose_name='Дата оплаты', max_length=200, blank=True)
payment_type = models.CharField(verbose_name='Форма оплаты', max_length=200, blank=False)
service = models.CharField(verbose_name='Услуга', max_length=200, blank=False)
quantity = models.IntegerField(blank=False)
price = models.FloatField(blank=False)
class Day(models.Model):
date = models.DateField(auto_now=False, auto_now_add=False)
price = models.FloatField()
payment_method = models.CharField(max_length = 200, blank=True)
payment_date = models.CharField(max_length=200, blank=True)
room = models.ForeignKey(Room, null=True, blank=True, verbose_name='Номер', on_delete=models.CASCADE)
class Room(models.Model):
name = models.CharField(max_length = 200, null=True)
id = models.AutoField(primary_key=True)
room_id = models.CharField(max_length = 200, null=False)
def __unicode__(self):
return self.name
serializers
class ReservationSerializer(serializers.ModelSerializer):
reserved_days = DaySerializer(many=True)
additional_services = AdditionalServicesSerializer(many=True)
class Meta:
model = Reservation
fields = [
'start',
'end',
'check_in_time',
'check_out_time',
'reserved_days',
'additional_services',
'has_refund',
'payed',
'guest_name',
'reservation_number',
]
class DaySerializer(serializers.ModelSerializer):
room = RoomSerializer()
class Meta:
model = Day
fields = [
'date',
'price',
'payment_method',
'payment_date',
'room',
]
class AdditionalServicesSerializer(serializers.ModelSerializer):
class Meta:
model = AdditionalService
fields = [
'payment_date',
'payment_type',
'service',
'quantity',
'price',
]
class RoomSerializer(serializers.ModelSerializer):
class Meta:
model = Room
fields = [
'room_id',
]
For serialization you don't need to use data keyword, just pass queryset as first positional argument:
serializer = ReservationSerializer(reservations, many=True)
return serializer.data
I have AbstractProfile model with predefined PRIVACY_CHOICES:
class AbstractProfile(models.Model):
PRIVACY_CHOICES = (
(1, _('all')),
(2, _('no one')),
)
title = models.CharField(_('title'), max_length=30)
info = models.TextField(_('information'), max_length=500, blank=True)
info_privacy = models.IntegerField(_('show information to'), default=1, choices=PRIVACY_CHOICES)
city = models.CharField(_('location'), max_length=30, blank=True)
city_privacy = models.IntegerField(_('show location to'), default=1, choices=PRIVACY_CHOICES)
address = models.CharField(_('address'), max_length=30, blank=True)
address_privacy = models.IntegerField(_('show address to'), default=1, choices=PRIVACY_CHOICES)
class Meta:
abstract = True
class UserProfile(AbstractProfile):
PRIVACY_CHOICES = (
(1, _('all')),
(2, _('friends')),
(3, _('friends of friends')),
(4, _('only me')),
)
title = None
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
names_privacy = models.IntegerField(_('show names to'), default=1, choices=PRIVACY_CHOICES)
birth_date = models.DateField(_('birth date'), null=True, blank=True)
birth_date_privacy = models.IntegerField(_('show birth date to'), default=1, choices=PRIVACY_CHOICES)
avatar = models.ImageField(upload_to='users/avatar', null=True, blank=True)
UserProfile should have fields from AbstractProfile, but with its own PRIVACY_CHOICES. In the current realisation PRIVACY_CHOICES of UserProfile does not override PRIVACY_CHOICES of AbstractProfile. How is it possible to solve? In the future could be other models, which also should have its own PRIVACY_CHOICES
I use Django 1.10
Found solution.
models.py:
class AbstractProfile(models.Model):
PRIVACY_CHOICES = (
(1, _('all')),
(2, _('no one')),
)
title = models.CharField(_('title'), max_length=30)
info = models.TextField(_('information'), max_length=500, blank=True)
info_privacy = models.IntegerField(_('show information to'), default=1, choices=PRIVACY_CHOICES)
city = models.CharField(_('location'), max_length=30, blank=True)
city_privacy = models.IntegerField(_('show location to'), default=1, choices=PRIVACY_CHOICES)
address = models.CharField(_('address'), max_length=30, blank=True)
address_privacy = models.IntegerField(_('show address to'), default=1, choices=PRIVACY_CHOICES)
class Meta:
abstract = True
class UserProfile(AbstractProfile):
PRIVACY_CHOICES = (
(1, _('all')),
(2, _('friends')),
(3, _('friends of friends')),
(4, _('only me')),
)
# NEW PIECE OF CODE
def __init__(self, *args, **kwargs):
def get_class_attrs(cls):
return re.findall(r'\w+(?=[,\)])', cls.__dict__['__doc__'])
super(UserProfile, self).__init__(*args, **kwargs)
all_fields = get_class_attrs(UserProfile)
for each_field in all_fields:
# all fields with '_privacy' in the name have 'choice' option
if '_privacy' in each_field:
self._meta.get_field(each_field).choices = self.PRIVACY_CHOICES
default_privacy_choice = self.PRIVACY_CHOICES[0][0]
if self._meta.get_field(each_field).default != default_privacy_choice:
self._meta.get_field(each_field).default = default_privacy_choice
# END OF NEW PIECE OF CODE
title = None
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
names_privacy = models.IntegerField(_('show names to'), default=1, choices=PRIVACY_CHOICES)
birth_date = models.DateField(_('birth date'), null=True, blank=True)
birth_date_privacy = models.IntegerField(_('show birth date to'), default=1, choices=PRIVACY_CHOICES)
avatar = models.ImageField(upload_to='users/avatar', null=True, blank=True)
class CompanyProfile(AbstractProfile):
pass
class OneMoreClass(AbstractProfile):
pass
Also is it necessary to modify forms.py:
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile() # old_version was: model = UserProfile
fields = ('title',
'first_name', 'last_name', 'names_privacy',
'birth_date', 'birth_date_privacy',
'info', 'info_privacy',
'city', 'city_privacy', 'address', 'address_privacy',
'avatar',)
Unmodified form takes choices from Abstract class. Now it is not required to repeat the same fields in different classes. If all classes have its own versions of choices, then method def __init__ can be copied to those classes with proper modifications (at least to change the class name), or even can be made as a separate function, but this is another story.
I was wondering if it's possible to have a filter over inline fields in the change_list template.
I have this models:
class VisitaVirtual(models.Model):
poi = models.ForeignKey(Poi)
cliente = models.ForeignKey(Cliente, verbose_name=_(u'Cliente'))
titulo = models.CharField(_(u'Título'), max_length=200)
observacoes = models.TextField(_(u'Observações'), null=True, blank=True)
exclusivo = models.BooleanField(_(u'Exclusivo'), default=False)
remover = models.BooleanField(_(u'Remover'), default=False, null=True, blank=True)
created = models.DateTimeField(_(u'Criado em'), auto_now_add=True, editable=False)
updated = models.DateTimeField(_(u'Modificado em'), auto_now=True, editable=False)
class FicheiroVisitaVirtual(models.Model):
visita_virtual = models.ForeignKey(VisitaVirtual, verbose_name=_(u'Visita virtual'))
ficheiro = models.FileField(_(u'Ficheiro'), upload_to='multimedia/visitas_virtuais/ficheiros/')
tipo = models.CharField(_(u'Tipo'), max_length=10, null=True, blank=True, choices=TIPO_VV)
linguagem = models.CharField(_(u'Linguagem'), choices=LANGUAGES, max_length=2)
created = models.DateTimeField(_(u'Criado em'), auto_now_add=True, editable=False)
updated = models.DateTimeField(_(u'Modificado em'), auto_now=True, editable=False)
and my admin.py looks like this:
class FicheiroVisitaVirtualModelInlines(admin.TabularInline):
model = FicheiroVisitaVirtual
extra = 3
list_filter = ['tipo']
class VisitaVirtualAdmin(admin.ModelAdmin):
list_display = ['titulo', 'cliente', 'remover', 'exclusivo', 'created', 'updated']
list_filter = ['created']
search_fields = ['titulo']
ordering = ['titulo']
raw_id_fields = ['poi', 'cliente']
inlines = [FicheiroVisitaVirtualModelInlines]
I need to have a filter in tipo field which so I can filter VisitaVirtual which have FicheiroVisitaVirtual of some time.
Is it possible?
You can use fields of related models in list_filter using the <related_manager>__<related field> syntax:
class VisitaVirtualAdmin(admin.ModelAdmin):
list_display = ['ficheirovisitavirtual_set__tipo', ]
(...)
I'm trying to make a custom backend for my system and I've hit a bit of a snag....I want to give users the ability to add new makes/models/series that are not already in the system via a form. I'm wondering how I'll go about this...my models look as below:
class Manufacturer(models.Model):
MANUFACTURER_POPULARITY_CHOICES = (
('1', 'Primary'),
('2', 'Secondary'),
('3', 'Tertiary'),
)
manufacturer = models.CharField(max_length=15, blank=False)
date_added = models.DateField()
manufacturer_popularity = models.CharField(max_length=1,
choices=MANUFACTURER_POPULARITY_CHOICES)
def __unicode__(self):
return self.manufacturer
class Model(models.Model):
model = models.CharField(max_length=20, blank=False)
manufacturer = models.ForeignKey(Manufacturer)
date_added = models.DateField()
def __unicode__(self):
name = ''+str(self.manufacturer)+" "+str(self.model)
return name
class Series(models.Model):
series = models.CharField(max_length=20, blank=True, null=True)
model = models.ForeignKey(Model)
date_added = models.DateField()
def __unicode__(self):
name = str(self.model)+" "+str(self.series)
return name
class Engine(models.Model):
ENGINE_TYPE_CHOICES = (
('H', 'H'),
('I', 'I'),
('R', 'R'),
('V', 'V'),
('W', 'W'),
)
FUEL_TYPE_CHOICES = (
('G', 'Gas'),
('D', 'Diesel'),
)
size = models.DecimalField(max_digits=2, decimal_places=1)
type = models.CharField(max_length=1, choices=ENGINE_TYPE_CHOICES)
cylinders = models.PositiveSmallIntegerField()
spec = models.CharField(max_length=20, blank=True, null=True)
fuel_type = models.CharField(max_length=1, choices=FUEL_TYPE_CHOICES)
class CommonVehicle(models.Model):
year = models.ForeignKey(Year)
series = models.ForeignKey(Series)
engine = models.ForeignKey(Engine)
body_style = models.ForeignKey(BodyStyle)
transmission = models.ForeignKey(Transmission)
speeds = models.PositiveSmallIntegerField()
drive_train = models.ForeignKey(DriveTrain)
horse_power = models.PositiveSmallIntegerField()
litre_100km_city = models.DecimalField(max_digits=3, decimal_places=1)
litre_100km_hwy = models.DecimalField(max_digits=3, decimal_places=1)
def __unicode__(self):
name = ''+str(self.year)+" "+str(self.series)
return name
This seems to be a fairly standard job for a django model form. I would recommend following the documentation at http://docs.djangoproject.com/en/dev/topics/forms/modelforms/. There are detailed instructions there on how to create a form from a model and then save the returned submission to the database.