Django admin widget for custom-sorted relationship - django

I need some help at designing a model and widget for a custom-sorted M2M relationship. The typical application scenario would be books and authors. In particular, when the order of authors in a book does matter.
The current version of my Publication model is:
class Publication(models.Model):
"""
A scientific publication.
"""
class Meta:
verbose_name = _('Publication')
verbose_name_plural = _('Publications')
ordering = ['year',]
nickname = models.CharField(
max_length=16,
help_text=_(
'A mnemonic name that "idenfies" this publication.'\
' E.g., concept_drift. (lowcase letters and dashes only)'),
validators=[RegexValidator(regex=r'^[a-z]+(_[a-z]+)*$')])
title = models.CharField(
_('Title'),
max_length=1024)
year = models.CharField(
max_length=4,
choices=YEARS,
help_text=_('Year of publication'),
db_index=True)
month = models.PositiveSmallIntegerField(
choices=MONTHS,
db_index=True,
null=True,
blank=True)
authors = models.ManyToManyField(
Person,
related_name='publications',
blank=True,
null=True)
attachment = FileBrowseField(
_('Attachment'),
max_length=256,
format='File',
blank=True,
null=True)
notes = models.CharField(
_('Notes'),
max_length=512,
help_text=_('Notes, e.g., about the conference or the journal.'),
blank=True,
null=True)
bibtex = models.TextField(
verbose_name=_('BibTeX Entry'),
help_text=_('At this moment, the BibTeX is not parsed for content.'),
blank=True,
null=True)
abstract = models.TextField(
_('Abstract'),
blank=True,
null=True)
fulltext = FileBrowseField(
_('Fulltext'),
max_length=256,
format='Document',
blank=True,
null=True)
date_updated = models.DateField(
_('Last updated on'),
auto_now=True,
db_index=True)
citation_key = models.SlugField(
max_length=512,
editable=False,
db_index=True)
#models.permalink
def get_absolute_url(self):
return ('academic_publishing_publication', (), { 'object_id': self.id })
def __unicode__(self):
return u'%s %s' % (
self.title,
self.year)
and authors are of People class:
class Person(models.Model):
"""
A person in a research lab.
"""
class Meta:
verbose_name = _('Person')
verbose_name_plural = _('People')
ordering = [
'rank',
'last_name',
'first_name', ]
affiliation = models.ManyToManyField(
Organization,
blank=True,
null=True,
related_name='people')
public = models.BooleanField(
verbose_name=_('Public?'),
help_text=_('Toggle visibility on public pages.'),
default=False)
current = models.BooleanField(
help_text=_('Is he/she still in the group?'),
default=True)
rank = models.ForeignKey(
Rank,
verbose_name=_('Academic Rank'),
related_name='people',
blank=True,
null=True)
first_name = models.CharField(
_('First Name'),
max_length=64)
mid_name = models.CharField(
blank=True,
null=True,
max_length=64)
last_name = models.CharField(
_('Last Name'),
max_length=64)
e_mail = models.EmailField(
_('E-mail'),
blank=True,
null=True)
web_page = models.URLField(
_('Web page'),
blank=True,
null=True)
description = models.TextField(
_('Description'),
blank=True,
null=True)
picture = FileBrowseField(
_('Profile picture'),
max_length=200,
format='Image',
blank=True,
null=True)
#models.permalink
def get_absolute_url(self):
return ('academic_people_person_detail', (), {'object_id': self.pk})
def __unicode__(self):
return u'%s' % self.name
def _get_name(self):
return u'%s %s' % (self.first_name, self.last_name)
name = property(_get_name)
I have two possibilities for storing the order of authors for each publication:
1. Explicit: make a AuthorForPublication model
class AuthorForPublication(models.Model):
author = ForeignKey(Person)
order = SmallPositiveInteger()
publication = ForeignKey(Publication)
but then a question arise: is it feasible to make an easy to use admin widget into Publication?
2. Workaround: create an authors_order field in Publication that takes a list of pks with a widget that lets the user re-order the authors. But this sounds a bit tricky.
Other alternatives certainly exist and are suggestions are appreciated.

I'd go for the first option. The second seems like a lot of work for very little (if any) gain.
When I need to have some explicit ordering, I always use a 'weight' column in the database.

Related

possible to split the model based on field in DRF admin.py

I have model named organization. I am using this same model model for 2 api's. I have a field code. one API do code auto generation another API takes user entry code. I want to separate the tables based on code. Autogeneration code starts SUB001,SUB002,.... like wise. user entry code thats userwish.
models.py
class Organization(models.Model):
code = models.CharField(max_length=255, null=False, unique=True)
name = models.CharField(max_length=255, null=False)
organization_type = models.CharField(max_length=255, choices=TYPES, null=False, default=COMPANY)
internal_organization = models.BooleanField(null=False, default=True)
location = models.ForeignKey(Location, on_delete=models.RESTRICT)
mol_number = models.CharField(max_length=255, null=True, blank=True)
corporate_id = models.CharField(max_length=255, null=True, blank=True)
corporate_name = models.CharField(max_length=255, null=True, blank=True)
routing_code = models.CharField(max_length=255, null=True, blank=True)
iban = models.CharField(max_length=255, null=True, blank=True)
description = models.TextField(null=True, blank=True)
total_of_visas = models.IntegerField(null=False, default=0)
base_currency = models.ForeignKey(Currency, on_delete=models.RESTRICT, null=True, blank=True, default=None)
logo_filename = models.ImageField(_("Image"), upload_to=upload_to, null=True, blank=True)
def __str__(self):
return self.name
admin.py
#admin.register(Organization)
class OrganizationAdmin(admin.ModelAdmin):
list_display = (
'id',
'code',
'name',
'location',
'organization_type',
'internal_organization',
'mol_number',
'corporate_id',
'corporate_name',
'routing_code',
'iban',
'description',
'total_of_visas',
'base_currency',
'logo_filename',
)
Is there any possible to split models based on code,.. Really Expecting help...
You can use Proxymodel inheritance. Documentation
class AutoGenerationManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(code__istartswith="SUB")
class AutoGeneration(Organization):
objects = AutoGenerationManager()
class Meta:
proxy = True
class UserGenerationManager(models.Manager):
def get_queryset(self):
return super().get_queryset().exclude(code__istartswith="SUB")
class UserGeneration(Organization):
objects = UserGenerationManager()
class Meta:
proxy = True

replacing dropdown lookup with related user field

In a form I have a drop down of usernames, this is referenced in the 'taken_by' field. I would like to display first_name and last_name, this is achieved through the __str__ but I can't seem to get it to function, the list of usernames are presented but not the firstname. Suggestions welcome.
from django.contrib.auth.models import User
from django.conf import settings
class Sample(models.Model):
sample_id = models.AutoField(primary_key=True)
area_easting = models.IntegerField(choices = EASTING_CHOICES)
area_northing = models.IntegerField(choices = NORTHING_CHOICES)
context_number = models.IntegerField()
sample_number = models.IntegerField()
material_type = models.CharField(max_length=200, default='', blank=True, null=True, choices = MATERIALS)
weight = models.DecimalField(max_digits=6, decimal_places=2)
description = models.CharField(max_length=500, default='', blank=True, null=True)
recovery_method = models.CharField(max_length=200, default='', blank=True, null=True, choices = RECOVERY_METHODS)
taken_by = models.ForeignKey(settings.AUTH_USER_MODEL, db_column='taken_by', on_delete = models.PROTECT)
comments = models.CharField(max_length=1000, default='', blank=True, null=True)
def __str__(self):
return self.taken_by.first_name
# return str(self.sample_id)
# return str(self.firstname)+ '-' +str(self.lastname)
# return u'%s %s' % (self.first_name, self.last_name)
Form setup as requested
class BotanySampleFilterForm(forms.ModelForm):
class Meta:
model = Sample
fields = (
# 'botany_id',
'sample_id',
'area_easting',
'area_northing',
'context_number',
'sample_number',
'material_type',
'weight',
'description',
'recovery_method',
'taken_by',
'comments'
)

I wanna create model which Before adding it must be accepted

I would like to create a model which must be accepted by the moderator before adding, after which every change in eg the title in this model must also be accepted
class MangaRequest(models.Model):
title = models.CharField(max_length=191)
type = models.CharField(max_length=30,choices=TYPE, blank=True, default='', null=True)
status= models.CharField(max_length=30, choices=STATUS, blank=True, default='', null=True)
date_start = models.DateField(blank=True, null=True)
data_end = models.DateField(blank=True, null=True)
age_restrictions = models.ForeignKey(OgraniczenieWiekowe, null=True, default='', blank=True)
volumes = models.SmallIntegerField(null=True, blank=True, default=0)
chapter = models.SmallIntegerField(null=True, blank=True, default=0)
is_accept = models.BooleanField(default=False)
delete = models.BooleanField(default=False)
This is my model and I have done it
def save(self, *args, **kwargs):
if self.is_accept == True:
manga = MangaAccept.objects.create(...)
super(MangaRequest, self).delete()
return manga
else:
super(MangaRequest, self).save()
And the same way is about deletes
My question is how can ACCEPT or REJECT for model and everyone field in this model ? Any sugestion ?

Dynamically generate fields+1 for model form

I have a model that is basically just a service report. I want this model to contain multiple punches (clock in\clock out). How do I go about doing that? When I pull up the form, I want to be able to add punches obviously.
class ServiceReportModel(models.Model):
report_number = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
site = models.ForeignKey(customers_models.SiteModel, on_delete=models.PROTECT)
request_number = models.ForeignKey(ServiceRequestModel,
on_delete=models.PROTECT,
null=True,
blank=True,
related_name='s_report_number'
)
reported_by = models.ForeignKey(main_models.MyUser, related_name='reports')
reported_date = models.DateTimeField(auto_now_add=True)
updated_by = models.ForeignKey(main_models.MyUser, blank=True, null=True, related_name='+')
updated_date = models.DateTimeField(auto_now=True)
equipment = models.ForeignKey(customers_models.EquipmentModel, on_delete=models.PROTECT)
report_reason = models.CharField(max_length=255, null=True)
time_in = models.DateTimeField(blank=True, null=True)
time_out = models.DateTimeField(blank=True, null=True)
actions_taken = models.TextField(null=False, blank=False)
recommendations = models.TextField(null=True, blank=True)
def get_absolute_url(self):
return reverse('service-report', kwargs={'pk': self.pk})
def __str__(self):
return '%s - %s, %s' % (self.site.company, self.reported_date.strftime('%d %B %Y'), self.equipment.name)
class Meta:
ordering = ['reported_date']
verbose_name = 'Service Report'
verbose_name_plural = 'Service Reports'

QuerySet Raised: Related Field got invalid lookup: icontains

Am learning Django and I used ForeignKey to link my models.
icontains work in field that are not ForeignKeys.
I want to filter the Items in my model to show me only fields that match the queryset.
But queryset raised: Related Field got invalid lookup: icontains
Please help. Below is My model and View
My Model
class Category(models.Model):
category = models.CharField(max_length=200, default='', blank=True, null=True)
def __unicode__(self):
return self.category
class StoreItems(models.Model):
item_name = models.CharField(max_length=200, default='', blank=True, null=True)
def __unicode__(self):
return self.item_name
class Supplier(models.Model):
supplier_name = models.CharField(max_length=200, default='', blank=True, null=True)
def __unicode__(self):
return self.supplier_name
class Unit(models.Model):
unit = models.CharField(max_length=200, default='', blank=True, null=True)
def __unicode__(self):
return self.unit
class Store(models.Model):
category = models.ForeignKey(Category, blank=True, null=True)
item_name = models.ForeignKey(StoreItems, blank=True, null=True)
quantity = models.IntegerField(default='', blank=True, null=False)
receive_amount = models.IntegerField(blank=True, null=True)
receive_by = models.CharField(max_length=120, default='', blank=True, null=False)
issue_amount = models.IntegerField(blank=True, null=True)
issue_by = models.CharField(max_length=120, default='', blank=True, null=True)
issue_to = models.CharField(max_length=120, default='', blank=True, null=True)
supplier_name = models.ForeignKey(Supplier, blank=True, null=True)
created_by = models.CharField(max_length=15, default='', blank=True, null=True)
unit = models.ForeignKey(Unit, blank=True, null=True)
reorder_level = models.IntegerField(default='0', blank=True, null=False)
export_to_CSV = models.BooleanField(default=False)
last_updated = models.DateTimeField(auto_now_add=False, auto_now=True)
My View
def store_list(request):
label = 'STORE'
title = 'Select the item you want to filter'
heading = 'SEARCH ITEMS'
if request.user.is_authenticated():
form = StoreSearchForm(request.POST or None)
context = {
"title": title,
"form": form,
"heading": heading,
}
if request.method == 'POST':
queryset = Store.objects.all().order_by('item_name').filter(category__icontains=form['category'].value(), item_name__icontains=form['item_name'].value())
context = {
"queryset": queryset,
"form": form,
}
return render(request, "store.html", context)
Yep, you can't directly use icontains on a foreign key but ...
Store.objects.all().order_by('item_name'
).filter(category__category__icontains=form['category'].value(), item_name__icontains=form['item_name'].value())
Your category model contains a field also called category. That can be accessed as category__category which means you can use a query such as the one given above.