is it possible to add an age field that is auto filled in the runtime based on another date of birth field at the django admin interface, i added a screenshot trying to explain more what i mean
my models.py
class FamilyMember(models.Model):
transaction = models.ForeignKey(Transaction, on_delete=models.CASCADE)
family_group = models.ForeignKey(FamilyGroup,
on_delete=models.CASCADE,
null=True,
blank=True)
name = models.CharField(max_length=100, null=True, blank=True)
date_of_birth = models.DateField(null=True, blank=True)
relationship = models.ForeignKey(Relationship, on_delete=models.PROTECT)
dependant_child_age_range = models.ForeignKey(DependantChildAgeRange,
null=True,
blank=True,
on_delete=models.PROTECT)
care_percentage = models.PositiveSmallIntegerField(
null=True, blank=True, validators=[
MaxValueValidator(100),
])
income = models.DecimalField(max_digits=6,
decimal_places=2,
null=True,
blank=True)
rent_percentage = models.PositiveSmallIntegerField(
null=True, blank=True, validators=[
MaxValueValidator(100),
])
admin.py
class FamilyMemberInline(admin.TabularInline):
def formfield_for_foreignkey(self, db_field, request, **kwargs):
action = request.META['PATH_INFO'].strip('/').split('/')[-1]
if action == 'change':
transaction_id = request.META['PATH_INFO'].strip('/').split('/')[-2]
if db_field.name == "family_group":
kwargs["queryset"] = FamilyGroup.objects.filter(transaction=transaction_id)
return super(FamilyMemberInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
model = FamilyMember
extra = 0
def sufficient_info_provided (self, obj):
return obj.sufficient_information_provided
sufficient_info_provided.boolean = True
readonly_fields = ['sufficient_info_provided',]
Override your inline's get_queryset method to annotate the queryset with the calculation. The annotation will add an age attribute to each object in the queryset.
Then as you can see in the ModelAdmin.list_display documentation, you can include a string representing a ModelAdmin method that accepts one argument, the model instance. Inline's work in the same way but you must include the method in ModelAdmin.readonly_fields.
Putting it all together:
class FamilyMemberInline(admin.TabularInline):
...
fields = (..., 'get_age')
readonly_fields = ('get_age',)
def get_queryset(self, request):
return (
super().get_queryset(request)
.annotate(age=...)
)
def get_age(self, instance):
return instance.age
Related
I want to calculate most popular post by each category, but i have this error DISTINCT ON fields is not supported by this database backend.
after i use PostgreSql, but I also had a error. annotation and distinct together did not work.
model -->
class Category(models.Model):
title = models.CharField(max_length=150, verbose_name=_("კატეგორია"))
def __str__(self):
return self.title
class Question(models.Model):
user = models.ForeignKey(
User, on_delete=models.CASCADE, verbose_name=_("მომხმარებელი")
)
category = models.ManyToManyField(Category)
title = models.CharField(max_length=150, verbose_name=_("სათაური"))
body = models.TextField(verbose_name=_("ტექსტი"))
image = models.ImageField(blank=True, null=True, verbose_name=_("ფოტო"))
link = models.URLField(
max_length=400,
blank=True,
null=True,
validators=[RequireHttpOrHttpsUrl()],
verbose_name=_("ლინკი"),
)
time = models.DateTimeField(auto_now=True)
send_notification = models.BooleanField(
default=True, verbose_name=_("გავაგზავნოთ შეტყობინება?")
)
def __str__(self):
return self.title
class LikeDislike(models.Model):
user = models.ForeignKey(
User, on_delete=models.CASCADE, verbose_name=_("მომხმარებელი")
)
question = models.ForeignKey(
Question, on_delete=models.CASCADE, verbose_name=_("კითხვა")
)
point = models.BooleanField()
time = models.DateTimeField()
def __str__(self):
return self.question.title
view ->
class CountLikeByCategory(generics.ListCreateAPIView):
serializer_class = CountLikeByCategorySerializer
def get_queryset(self):
query=Question.objects.values_list(
'category__title','title'
).annotate(
l=Count('likedislike',filter=Q(likedislike__point=1)),
d=Count('likedislike',filter=Q(likedislike__point=0)),
total=F('l')+F('d'),
).order_by('category', '-total').distinct('category')
return query
who can help me?
i wan correct query
try this:
def get_queryset(self):
query=Question.objects.values_list(
'category','category__title','title'
).annotate(
l=Count('likedislike',filter=Q(likedislike__point=1)),
d=Count('likedislike',filter=Q(likedislike__point=0)),
total=F('l')+F('d'),
).order_by('category', '-total').distinct('category')
return query
So I'm trying to add an extra field to a ModelForm class in the __init__ func, so that on the Create/Update class views I could grab this model and create a new model. Since the Model doesn't have this field, how could I add it in the __init__ func or is there some other way I could add this field?
I've tried overriding __init__ method to include this field in the ModelForm class, but this still throws me an error that the argument is unexpected
class MeterInstallationForm(ModelForm):
class Meta:
model = MeterInstallation
fields = METER_INSTALLATION_DEFAULT_FIELDS
def __init__(self, *args, **kwargs):
instance = kwargs.get("instance")
super(MeterInstallationForm, self).__init__(*args, **kwargs)
if instance:
# get tariff info in the form
# self.fields["tariff"] = instance.tariff
self.fields["tariff"] = TariffApplication.objects.filter(meter_installation__pk=instance.meter_installation.pk).values_list("tariff", flat=True)
class MeterInstallationCreateView(MeterInstallationsViewMixin, LoginRequiredMixin, CreateView):
template_name = "meter_installations/meter_installation_create.html"
fields = (
"name",
"meter_type",
"parent",
"meter",
"building",
"initial_reading",
"final_reading",
"active_after",
"active_until",
"comment",
)
form_class = MeterInstallationForm
meter_installation_create_view = MeterInstallationCreateView.as_view()
class MeterInstallation(ActiveAfterUntilModel, DateTrackedModel, MPTTModel, NamedModel): # type: ignore
meter_type = models.ForeignKey(
MeterType,
on_delete=models.PROTECT,
null=False,
blank=False,
related_name="installations",
verbose_name=_("Meter Installation type"),
)
parent = TreeForeignKey(
"self", on_delete=models.CASCADE, null=True, blank=True, related_name="children", db_index=True
)
meter = models.ForeignKey(
Meter, on_delete=models.PROTECT, related_name="installations", null=False, blank=False, verbose_name=_("Meter")
)
building = models.ForeignKey(
Building,
on_delete=models.PROTECT,
related_name="meter_installations",
null=True,
blank=False,
verbose_name=_("Building"),
)
places = models.ManyToManyField(Place, related_name="meter_installations", blank=False, verbose_name=_("Places"))
initial_reading = models.DecimalField(
decimal_places=4, max_digits=10, null=False, blank=False, default=0, verbose_name=_("Initial reading")
)
final_reading = models.DecimalField(
decimal_places=4, max_digits=10, null=True, blank=True, default=0, verbose_name=_("Final reading")
)
class MPTTMeta:
order_insertion_by = ["meter"]
def get_absolute_url(self):
return reverse("meter-installations:meter-installation-detail", kwargs={"pk": self.pk})
def delete(self, *args, **kwargs):
first_lvl_children = self.get_children().filter(level=1)
for first_lvl_child in first_lvl_children:
first_lvl_child.parent = None
first_lvl_child.save()
for leaf in first_lvl_child.get_children():
leaf.parent = first_lvl_child
leaf.save()
tree_id = first_lvl_child.tree_id
MeterInstallation.objects.partial_rebuild(tree_id)
super(MeterInstallation, self).delete(*args, **kwargs)
def __str__(self):
return f"[{self.pk}] type: {self.meter_type_id}, meter: {self.meter_id}"
class Tariff(ActiveAfterUntilModel, NamedModel, DateTrackedModel):
tariff_type = models.ForeignKey(
MeterType,
on_delete=models.PROTECT,
null=False,
blank=False,
related_name="tariffs",
verbose_name=_("Tariff type"),
)
building = models.ForeignKey(
Building, on_delete=models.PROTECT, related_name="tariffs", null=True, blank=False, verbose_name=_("Building")
)
unit_name = models.CharField(max_length=100, null=False, blank=True, unique=False, verbose_name=_("Unit name"))
unit_price = models.DecimalField(
decimal_places=4, max_digits=10, null=False, blank=False, default=0.0, verbose_name=_("Unit price")
)
VAT = models.DecimalField(decimal_places=2, max_digits=10, null=True, blank=True, verbose_name=_("VAT"))
class Meta:
unique_together = ("name", "tariff_type", "active_after", "active_until")
def get_absolute_url(self):
return reverse("tariffs:tariff-detail", kwargs={"pk": self.pk})
def __str__(self) -> str:
return (
f"[{self.pk}] "
f"type: {self.tariff_type_id}, "
f"building: {self.building_id}, "
f"price: {self.unit_price}, "
f"VAT: {self.VAT}, "
f"active_until: {self.active_until}"
)
class TariffApplication(ActiveAfterUntilModel, DateTrackedModel): # type: ignore
tariff = models.ForeignKey(
Tariff,
on_delete=models.PROTECT,
null=False,
blank=False,
related_name="tariff_applications",
verbose_name=_("Tariff Applications"),
)
meter_installation = models.ForeignKey(
"MeterInstallation",
on_delete=models.PROTECT,
null=False,
blank=False,
related_name="tariff_applications",
verbose_name=_("Meter Installation"),
)
def __str__(self) -> str:
return f"[{self.pk}] tariff: {self.tariff_id}, meter installation: {self.meter_installation_id}"
I would love to know how to make this work, so that in my CreateView I could start creating a third model by the given Tariff
You can use a ModelChoiceField so that you can select a tariff on the form.
class MeterInstallationForm(ModelForm):
class Meta:
model = MeterInstallation
fields = METER_INSTALLATION_DEFAULT_FIELDS
def __init__(self, *args, **kwargs):
super(MeterInstallationForm, self).__init__(*args, **kwargs)
self.fields["tariff"] = forms.ModelChoiceField(queryset=Tariff.objects.all())
Then in your form_valid() method, you can retrieve the tariff from cleaned_data and create the related TariffApplication.
def form_valid(self, form):
instance = form.save()
TariffApplication.objects.create(tariff=form.cleaned_data['tariff'], meter_installation=instance)
return HttpResponseRedirect(self.get_success_url())
You may need to change the queryset if you need to filter the list of available tariffs. In your original question, I don't think it makes sense to have if instance in the form's __init__ method, because an instance won't be passed to the form for a CreateView.
You can include extra field in your ModelForm and set that in your view such as:
# forms.py
class MeterInstallationForm(ModelForm):
class Meta:
model = MeterInstallation
fields = METER_INSTALLATION_DEFAULT_FIELDS + ('tariff',)
# views.py
class MeterInstallationCreateView(MeterInstallationsViewMixin, LoginRequiredMixin, CreateView):
template_name = "meter_installations/meter_installation_create.html"
fields = (
"name",
"meter_type",
"parent",
"meter",
"building",
"initial_reading",
"final_reading",
"active_after",
"active_until",
"comment",
)
form_class = MeterInstallationForm
def form_valid(self, form):
form.instance.tariff = forms.TariffApplication(form.data)
return super().form_valid(form)
I have a created Django-CMS Plugin with a ManytoManyField to another model. When creating the Plugin on the Front-End, i want the user to be able to filter the ManytoManyField list (which might be too long).
By the way this future is already on Django admin:
class ModelAdmin(admin.ModelAdmin):
list_filter = ('field_name', )
form = PartnerLogoTableForm
Is it possible to have something similar like that on my
cms_plugins.py:
class PartnerLogoTablePlugin(CMSPluginBase):
model = LogoTablePlugin
form = LogoTablePluginForm
name = _('LogoTable Plugin')
render_template = False
search_fields = ('description',)
def render(self, context, instance, placeholder):
self.render_template = 'aldryn_logo_tables/plugins/%s/logotable.html' % instance.style
context.update({
'object': instance,
'placeholder': placeholder,
})
return context
plugin_pool.register_plugin(PartnerLogoTablePlugin)
models.py:
class PartnerLogoTable(models.Model):
name = models.CharField(_('Partner name'), max_length=255)
image = FilerImageField(verbose_name=_('Image'), null=True, blank=True, on_delete=models.SET_NULL)
partner_url = models.TextField(_('Partner url'), null=True, blank=True, validators=[URLValidator()])
is_active = models.BooleanField(_('Is active'), blank=True, default=True)
created_at = models.DateTimeField(_('Created at'), auto_now_add=True)
updated_at = models.DateTimeField(_('Updated at'), auto_now=True)
order = models.IntegerField(_('Order'), null=True, blank=True)
class Meta:
verbose_name = _('Partner Logo')
verbose_name_plural = _('Partner Logos')
ordering = ['order']
def __str__(self):
return self.name
class LogoTablePlugin(CMSPlugin):
DEFAULT = 'default'
LOGOTABLE_CHOICES = [
(DEFAULT, _('Default')),
]
description = models.CharField(_('Description'), max_length=255, null=True, blank=True)
partner = models.ManyToManyField(PartnerLogoTable, verbose_name=_('Partner'))
logo_per_row = models.IntegerField(_('Logo per line'), default=1, null=True, blank=True,
validators=[MaxValueValidator(4), MinValueValidator(1)],
help_text=_('Number of logos to be displayed per row'))
style = models.CharField(_('Style'), choices=LOGOTABLE_CHOICES + get_additional_styles(), default=DEFAULT,
max_length=50, blank=True, null=True, )
class Meta:
verbose_name = _('Partner Logo Plugin')
verbose_name_plural = _('Partner Logo Plugins')
def __unicode__(self):
return u'%s' % self.description
forms.py
class LogoTablePluginForm(forms.ModelForm):
model = LogoTablePlugin
def clean_style(self):
.....
return style
class PartnerLogoTableForm(forms.ModelForm):
model = PartnerLogoTable
def clean(self):
....
return self.cleaned_data
This is how the plugin looks now
ModelSelect2Multiple from django-autocomplete-light seems perfect for your use case.
I'm trying to update other table after successful delete of of data. Below is my
views.py
class AttendeeDeleteView(DeleteView):
model = Attendee
success_url = reverse_lazy('index')
def get_form_kwargs(self):
id = self.kwargs['id'] # get value of enr
Payment.objects.filter(pk=id).update(registered=0)
In my urls.py
url(r'^delete/(?P<pk>\d+)$', AttendeeDeleteView.as_view(template_name="includes/attendee_delete.html"), name='attendee_delete',),
My Current code successfully delete the item but failed to update the other table.
my model
class Payment(models.Model):
id = models.AutoField(primary_key=True)
payee = models.CharField(max_length=200, blank=True, null=True)
contact = models.CharField(max_length=200,blank=True, null=True)
batch = models.CharField(max_length=200, null=True, blank=True)
ticketNumber = models.CharField(max_length=200)
ticketType = models.CharField(max_length=200, choices=TICKET_CHOICES, default='paid')
date = models.DateField('Date Paid (MM/DD/YYYY)', max_length=200, null=True, blank=True)
remarks = models.CharField(max_length=200 ,blank=True, null=True)
registered = models.BooleanField(default=False)
def __str__(self):
return self.payee
class Attendee(models.Model):
id = models.AutoField(primary_key=True)
payment = models.OneToOneField(Payment, on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length=200)
batch = models.CharField(max_length=200, blank=True, null=True)
department = models.CharField(max_length=200, choices=DEPT_CHOICES, default='')
remarks = models.CharField(max_length=200, blank=True, null=True)
UPDATE 1:
I followed this came up with
def get(self, request, *args, **kwargs):
id = kwargs['pk'] # get value of enr
context = Payment.objects.filter(pk=id).update(registered=0)
return self.render_to_response(context)
but it returned context must be a dict rather than int.
I think def get_form_kwargs(self): doesn't executed, because it used for FormMixin. But, you can also handle it inside get() function.
def get(self, request, *args, **kwargs):
attendee = self.get_object()
Payment.objects.filter(pk=attendee.payment.pk).update(registered=0)
context = self.get_context_data(object=attendee)
return self.render_to_response(context)
See this https://ccbv.co.uk/projects/Django/1.11/django.views.generic.edit/DeleteView/ for more..
Edit:
This solution below if still getting a problem when using get() method.
from django.http import HttpResponseRedirect
....
def delete(self, request, *args, **kwargs):
"""
Calls the delete() method on the fetched object and then
redirects to the success URL.
"""
self.object = self.get_object()
success_url = self.get_success_url()
Payment.objects.filter(pk=self.object.payment.pk).update(registered=0)
self.object.delete()
return HttpResponseRedirect(success_url)
More than one day trying to figure out on how to use the Django Admin list_filter on a QuerySet using .extra()
In the AdAdmin I need to add one new column 'ad_hist_status_id' from the model AdHist so I can use this portion of the code on SomeListFilter:
def queryset(self, request, queryset):
return queryset.filter(ad_hist_status_id=self.value())
It looks like impossible. Doing this with sql is easy:
select a.*, ah.ad_hist_status_id from ad_ad a
join ad_adhist ah on ah.ad_id = a.id
where
ah.datetime_end is null
order by a.id DESC
Until now I cannot make to work this SomeListFilter in the Django Admin, the error is:
FieldError at /admin/ad/ad/
Cannot resolve keyword 'ad_hist_status_id' into field.
Choices are: addetailscategories, address, adhist, adphotos,
adprice, adscheduleinfo, age, comment, county, county_id,
date_inserted, date_updated, description, district, district_id,
email, id, lat, lng, name, parish, parish_id, schedule_type,
schedule_type_id, telephone, title, user_inserted, user_inserted_id,
user_updated, user_updated_id
My question is, how do I effectively add a new column to a QuerySet and then how can I query this new QuerySet with the new column?
Some portions of my code bellow
The Models:
class Ad(models.Model):
title = models.CharField(max_length=250)
name = models.CharField(max_length=100)
description = models.TextField()
age = models.IntegerField(blank=True, null=True)
telephone = models.CharField(max_length=25)
email = models.EmailField()
district = models.ForeignKey(District)
county = ChainedForeignKey(County, chained_field="district", chained_model_field="district", sort=True) # smart_selects app
parish = ChainedForeignKey(Parish, chained_field="county", chained_model_field="county", sort=True) # smart_selects app
address = models.CharField(max_length=250, null=True, blank=True)
lat = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
lng = models.DecimalField(max_digits=9, decimal_places=6, null=True, blank=True)
schedule_type = models.ForeignKey(AdScheduleType)
comment = models.TextField(null=True, blank=True)
user_inserted = models.ForeignKey(User, null=True, blank=True, related_name='user_inserted_ad')
date_inserted = models.DateTimeField(auto_now_add=True)
user_updated = models.ForeignKey(User, null=True, blank=True, related_name='user_updated_ad')
date_updated = models.DateTimeField(null=True, blank=True)
def __str__(self):
return self.name
class AdHist(models.Model):
ad = models.ForeignKey(Ad)
datetime_begin = models.DateTimeField()
datetime_end = models.DateTimeField(null=True, blank=True)
ad_hist_status = models.ForeignKey(AdHistStatus)
ad_hist_change_reason = models.ForeignKey(AdHistChangeReason)
comment = models.TextField(null=True, blank=True)
user_inserted = models.ForeignKey(User, null=True, blank=True, related_name='user_inserted_ad_hist')
date_inserted = models.DateTimeField(auto_now_add=True)
user_updated = models.ForeignKey(User, null=True, blank=True, related_name='user_updated_ad_hist')
date_updated = models.DateTimeField(null=True, blank=True)
def __str__(self):
return self.ad.name
The Admin:
class SomeListFilter(admin.SimpleListFilter):
title = _('Approval State')
parameter_name = 'ad_hist_status_id'
def lookups(self, request, model_admin):
return (
('1', _('Approved')),
('4', _('Not Approved')),
)
def queryset(self, request, queryset):
return queryset.filter(ad_hist_status_id=self.value())
class AdAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'title', 'age', 'telephone',
'email', 'district', 'county', 'parish',
'ad_status', 'ad_hist_change_reason', 'comment',
'user_inserted', 'date_inserted', 'user_updated',
'date_updated', 'ad_hist_status_id')
readonly_fields = ('ad_status', 'id', 'ad_hist_change_reason',
'ad_hist_status_id')
list_filter = (SomeListFilter,)
def get_queryset(self, request):
qs = super(AdAdmin,self).get_queryset(request).extra(select={'ad_hist_status_id': 'select ad_hist_status_id from ad_adhist where ad_adhist.ad_id = ad_ad.id and ad_adhist.datetime_end is null'},)
return qs
def ad_hist_status_id(self, inst):
return inst.ad_hist_status_id
Can someone give me a clue?
Best Regards
If I understand your question right, you are looking for this:
from django.db.models import F
def queryset(self, request, queryset):
return queryset.filter(ad_hist_status__id=F('id'))
The F expression is used to reference a field from the same model, and to refer a field from a related model, you need to use an underscore (__).
Take a closer look to Django field lookups. Look at what the docs say:
Basic lookups keyword arguments take the form field__lookuptype=value. (That’s a double-underscore).
You want to take the AdHist related object from Ad, which has a related AdHistStatus, and get its id.
So you should access this id field like:
def ad_hist_status_id(self, instance):
return instance.adhist.ad_hist_status.id
Or you can list it directly with the double-underscore syntax:
class AdAdmin(admin.ModelAdmin):
list_display = (..., 'adhist__ad_hist_status__id')