Saving Auto-Incrementing line number in Inline field Django - python

I have the following model as an inline field in another model:
class route_ordering(models.Model):
route_id = models.ForeignKey(route, on_delete=models.CASCADE)
activity_id = models.ForeignKey(activity, on_delete=models.CASCADE)
day = models.IntegerField()
order = models.IntegerField()
And in the admin.py:
class RouteAdmin(admin.ModelAdmin):
inlines = (RouteOrderingInline,)
I would like to make "order" self-incrementing from one, so it will be auto filled when I go to the Django admin panel (in the first line order=1 , then order-2 etc.)
I know you can use Default to set an autofilled value, but I want it to increment by itself.
How can I do this?

I can't guarantee this will work, and I'm not able to test out right now, but I think you can pass in a generator to your default value arg.
define increment():
return range(1, 1000)
And wherever your passing in a default just call next(increment())
Sorry I can't provide a more detailed example, I'm writing this on my phone XD, but I think that should work.

Related

Django models: set default IntegerField to number of instances

I would like to set the "order" IntegerField of my Achievement model to the current count of objects in Achievement. The order field is used to order achievements, and users can change it. For now I have 1 as default.
class Achievement(models.Model):
title = models.CharField(max_length=50, blank=True)
description = models.TextField()
order = models.IntegerField(default=1) #Get the number of achievement objects
class Meta:
db_table = 'achievement'
ordering = ['order', 'id']
For example, if I already have one achievement in my database with whatever order the next one should get order=2 by default.
As far as I understood, you want to have a default value of 1 to the order integer field and increment it with each entry of Achievment (same functionality as the id), but also allow users change it.
For this purpose you can use Django's AutoField:
An IntegerField that automatically increments according to available IDs. You usually won’t need to use this directly; a primary key field will automatically be added to your model if you don’t specify otherwise.
Like this:
class Achievement(models.Model):
...
order = models.AutoField(default=1, primary_key=False)
# Also specify that this autofield is *not* a ^ primary key
class Meta:
ordering = ['order', 'id']

Design an observation pattern in Django Rest Framework

I want to implement something like the pattern which introduced in this answer. For example I have four models like this:
class Protperty(models.Model):
property_type = models.CharField(choices=TYPE_CHOICES, default='float', max_length=100)
property_name = models.CharField(max_length=100)
class FloatProperty(models.Model):
property_id = models.ForeignKey(Property, related_name='value')
value = models.FloatField(default=0.0)
class IntProperty(models.Model):
property_id = models.ForeignKey(Property, related_name='value')
value = models.IntField(default=0)
class StringProperty(models.Model):
property_id = models.ForeignKey(Property, related_name='value')
value = models.CharField(max_lenght=100, blank=True, default='')
After defining these classes, I do not know how I must implement serializer or view classes. For example for writing serializer I want to put a field value, which must be set depend of type of object currently is serialized or deserialilzed(property_type defines it).
I am new to django and rest framework too, please give me some suggestions for implementing such models and serializers.
Edit:
In general I want to construct some models that using them I able to store run time defining property with different values and able to query them further. For example I have a store and it has different goods which each one has specific property and I want to query them using a specific property.

How to use unique_together method in django views

class Model1(models.Model):
username = models.CharField(max_length=100,null=False,blank=False,unique=True)
password = models.CharField(max_length=100,null=False,blank=False)
class Model2(models.Model):
name = models.ForeignKey(Model1, null=True)
unique_str = models.CharField(max_length=50,null=False,blank=False,unique=True)
city = models.CharField(max_length=100,null=False,blank=False)
class Meta:
unique_together = (('name', 'unique_str'),)
I've already filled 3 sample username-password in Model1 through django-admin page
In my views I'm getting this list as
userlist = Model1.objects.all()
#print userlist[0].username, userlist[0].password
for user in userlist:
#here I want to get or create model2 object by uniqueness defined in meta class.
#I mean unique_str can belong to multiple user so I'm making name and str together as a unique key but I dont know how to use it here with get_or_create method.
#right now (without using unique_together) I'm doing this (but I dont know if this by default include unique_together functionality )
a,b = Model2.objects.get_or_create(unique_str='f3h6y67')
a.name = user
a.city = "acity"
a.save()
What I think you're saying is that your logical key is a combination of name and unique_together, and that you what to use that as the basis for calls to get_or_create().
First, understand the unique_together creates a database constraint. There's no way to use it, and Django doesn't do anything special with this information.
Also, at this time Django cannot use composite natural primary keys, so your models by default will have an auto-incrementing integer primary key. But you can still use name and unique_str as a key.
Looking at your code, it seems you want to do this:
a, _ = Model2.objects.get_or_create(unique_str='f3h6y67',
name=user.username)
a.city = 'acity'
a.save()
On Django 1.7 you can use update_or_create():
a, _ = Model2.objects.update_or_create(unique_str='f3h6y67',
name=user.username,
defaults={'city': 'acity'})
In either case, the key point is that the keyword arguments to _or_create are used for looking up the object, and defaults is used to provide additional data in the case of a create or update. See the documentation.
In sum, to "use" the unique_together constraint you simply use the two fields together whenever you want to uniquely specify an instance.

Putting in extra restrictions when filtering on foreignkey in django-admin

When getting members based on Unit, I only want to get the ones who are actually in that unit as of now.
I've got a model looking like this:
class Member(models.Model):
name = models.CharField(max_length=256)
unit = models.ManyToManyField(Unit, through='Membership')
class Membership(models.Model):
member = models.ForeignKey(Member)
unit = models.ForeignKey(Unit)
start = models.DateField(default=date.today)
stop = models.DateField(blank=True, null=True)
class Unit(models.Model):
name = models.CharField(max_length=256)
As you can see, members can have a "fake" membership in unit, that is only history and should not be considered in the searches and listings of the admin. They should be shown in the change-page for a single object though.
The admin looks like this:
class MembershipInline(admin.TabularInline):
model = Membership
extra = 1
class MemberAdmin(admin.ModelAdmin):
list_filter = ('unit',)
inlines = [MembershipInline,]
So how can I (if at all possible this way), when filtering on unit only get those units whose membership__stop__isnull=True?
I tried Managers, I can make them work on the model in the admin itself, but not on the filtering/searches. There is also a def queryset(self) method that is overrideable, but I can't wrap my head around how to use it to fix my problem.
Edit, how this is used: A member has only one membership in a unit, however, they could be members from before, but they are ended (with stop). So I only want to filter (and show, in the list view) those members who have an open-ended membership (like, that they are members of that unit now).
Any ideas?
So you're trying to get the members of a specific Unit, right?
unit = Unit.objects.select_related().get(id=some_id)
This will pull the unit out of the database for you, along with the Memberships and Users that belong to it. You can access and filter the users by:
for member in unit.membership__set.filter(stop__isnull=True):
print member.name
I hope this helps? I may be wrong, I haven't tested this.
One way to certainly achieve this is by adding a denormalized field for
has_open_ended_membership.
To do this just add a BooleaneField like that to the Member and make sure it's consistent.
From the django documentation this seems to be the only way without writing specialized code in the ModelAdmin object:
Set list_filter to activate filters in
the right sidebar of the change list
page of the admin. This should be a
list of field names, and each
specified field should be either a
BooleanField, CharField, DateField,
DateTimeField, IntegerField or
ForeignKey.
I'm curious about other approaches - list_filter certainly is limited.
I fixed it with putting in a denormalized field in member, with a foreign-key to the active unit. Then, to make it work and be automatically updated in the admin, I made the specialized save-function for Membership.
class Member(models.Model):
name = models.CharField(max_length=256)
unit = models.ManyToManyField(Unit, through='Membership')
unit_denorm = models.ForeignKey(Unit)
class Membership(models.Model):
member = models.ForeignKey(Member)
unit = models.ForeignKey(Unit)
start = models.DateField(default=date.today)
stop = models.DateField(blank=True, null=True)
def save(self, *args, **kwargs):
if not self.stop:
self.member.unit_denorm = self.unit
self.member.save()
super(Membership, self).save(*args, **kwargs)
class Unit(models.Model):
name = models.CharField(max_length=256)
And with list_filter = ('unit_denorm',) in the admin, it does exactly what I want.
Great! Of course, there should only be one field with stop__isnull=True. I haven't figured out how to make that restriction. but people using the system know they shouldn't do that anyway.

How to get Django admin.TabularInline to NOT require some items

class LineItemInline(admin.TabularInline):
model = LineItem
extra = 10
class InvoiceAdmin(admin.ModelAdmin):
model = Invoice
inlines = (LineItemInline,)
and
class LineItem(models.Model):
invoice = models.ForeignKey(Invoice)
item_product_code = models.CharField(max_length=32)
item_description = models.CharField(max_length=64)
item_commodity_code = models.ForeignKey(CommodityCode)
item_unit_cost = models.IntegerField()
item_unit_of_measure = models.ForeignKey(UnitOfMeasure, default=0)
item_quantity = models.IntegerField()
item_total_cost = models.IntegerField()
item_vat_amount = models.IntegerField(default=0)
item_vat_rate = models.IntegerField(default=0)
When I have it setup like this, the admin interface is requiring me to add data to all ten LineItems. The LineItems have required fields, but I expected it to not require whole line items if there was no data entered.
That's strange, it's supposed not to do that - it shouldn't require any data in a row if you haven't entered anything.
I wonder if the default options are causing it to get confused. Again, Django should cope with this, but try removing those and see what happens.
Also note that this:
item_unit_of_measure = models.ForeignKey(UnitOfMeasure, default=0)
is not valid, since 0 can not be the ID of a UnitOfMeasure object. If you want FKs to not be required, use null=True, blank=True in the field declaration.
Turns out the problem is default values. The one pointed out above about UnitOfMeasure isn't the actual problem though, any field with a default= causes it to require the rest of the data to be present. This to me seems like a bug since a default value should be subtracted out when determining if there is anything in the record that needs saving, but when I remove all the default values, it works.
In this code,
item_unit_of_measure = models.ForeignKey(UnitOfMeasure, default=0)
it was a sneaky way of letting the 0th entry in the database be the default value. That doesn't work unfortunately as he pointed out though.

Categories