Django: I am unable to get Django to autocreate an autofield - python

I am calling BORROWER.objects.create(ssn=Ssn, bname=Name, address=Address, phone=Phone) from views.py to create an entry in my sqlite database. This is my models.py file with the relevant function.
class BORROWER(models.Model):
card_id = models.AutoField(primary_key=True, max_length=7)
ssn = models.CharField(max_length=11)
bname = models.CharField(max_length=71)
address = models.CharField(max_length=79)
phone = models.CharField(max_length=15)
def __str__(self):
return str(self.card_id)
The database entry is successfully created. However, since I am not specifying a value for the card_id field, the value stays as (<django.db.models.fields.AutoField>,) instead of an actual key. When I try to specify a value for card_id it says something about unexpected argument. Am I calling the create function incorrectly?
Edit: The comma is not there in the original code, but I will try with the suggested edits

Remove comma at the end of the card_id and don't use max_length with AutoFiled ..
class BORROWER(models.Model):
card_id = models.AutoField(primary_key=True)
ssn = models.CharField(max_length=11)
bname = models.CharField(max_length=71)
address = models.CharField(max_length=79)
phone = models.CharField(max_length=15)
def __str__(self):
return str(self.card_id)

Related

Django form: Update model values based on user input in one field

I am writing a form to let a user enter a purchase from the template. A couple things need to happen:
the purchase goes to populate a row in the replenishment table
some fields of the replenishment table get updated based on what the user has input
here is what my model look like:
class replenishment(models.Model):
Id = models.CharField(max_length=100, primary_key=True, verbose_name= 'references')
Name = models.CharField(max_length=200)
Quantity = models.FloatField(default=0)
NetAmount = models.FloatField(default=0)
SupplierID = models.CharField(max_length=200)
Supplier = models.CharField(max_length=200)
SellPrice = models.FloatField(default=0)
StockOnOrder = models.FloatField(default=0)
StockOnHand = models.FloatField(default=0)
def __str__(self):
return self.reference
and the form:
class ProcurementOperationRecord(forms.Form)
Id = forms.CharField(required=True)
Quantity = forms.FloatField(required=True)
NetAmount = forms.FloatField(required=True)
Supplier = forms.CharField(required=True)
SellPrice = forms.FloatField(required=True)
I have no clue how to let the user input the values in form and automatically add Quantity to StockOnOrder as well as automatically recognize the SupplierID based on Supplier. At this point I don't know where to start really. At least, is it possible to achieve what I try to do?
First, I've changed some things around and added some comments to what and why I did them.
# models/classes in python are singular AND camel cased (99.9%)
class Supplier(models.Model):
...
# models/classes in python are singular AND camel cased (99.9%)
class Replenishment(models.Model):
# attributes are normally lower case and snake cased (99.9%)
# try not to do this, a CharField??, unless you're using a guid? if so use UUIDField()
# https://docs.djangoproject.com/en/3.1/ref/models/fields/#uuidfield
id = models.CharField(db_column='Id', max_length=100, primary_key=True, verbose_name='references')
name = models.CharField(db_column='Name', max_length=200)
quantity = models.FloatField(db_column='Quantity', default=0)
net_amount = models.FloatField(db_column='NetAmount', default=0)
# deleted your field "Supplier" -- with this change you can join to the other table and get what you need without having to duplicate anything
supplier = models.ForeignKey(Supplier, db_column='SupplierID')
sell_price = models.DecimalField(db_column='SellPrice', default=0, max_digits=6, decimal_places=2) # You're asking for trouble if you keep this as FloatField
stock_on_order = models.IntegerField(db_column='StockOnOrder', default=0) # how can you have ordered a .5 for your stock? changed to IntegerField
stock_on_hand = models.IntegerField(db_column='StockOnHand', default=0) # how can you have a .5 of your stock? changed to IntegerField
class Meta:
db_table = 'replenishment' # try not to do this either.. let django come up with the name.. unless you're using an existing database/table?
...
# models/classes in python are singular AND camel cased (99.9%)
# django has a standard that they normally postfix forms with "Form" at the end of the class (no matter if it's a ModelForm or regular Form)
class ProcurementOperationRecordForm(forms.ModelForm)
class Meta:
model = Replenishment
fields = ('id', 'quantity', 'net_amount', 'supplier', 'sell_price')
# I would remove the "id", the client shouldn't care or know about it..
Now to create and update. (This would live inside a view)
# creating?
form = ProcurementOperationRecordForm(data=request.POST)
if form.is_valid():
form.save()
return redirect(..) or render(..)
# updating?
replenishment = Replenishment.objects.get(id='...something')
form = ProcurementOperationRecordForm(data=request.POST, instance=replenishment)
if form.is_valid():
form.save()
return redirect(..) or render(..)
This is just a general idea. You can try something like this.
First get the user input values of quantity and supplier like this from the valid form.
quantity = form.cleaned_data.get('quantity')
supplier = form.cleaned_data.get('supplier')
Then you can update your replenishment model
replenishment.objects.filter(Supplier=supplier).update(StockOnOrder=quantity)

Django order by primary key does not work

I have a model as below:
class Photos(models.Model):
id = models.IntegerField(primary_key=True, default=1)
name = models.CharField(max_length=500)
size = models.IntegerField()
path = models.CharField(max_length=500)
date = models.DateField(default=datetime.now)
def __str__(self):
return self.date.strftime('%Y-%m-%d')
class Meta:
verbose_name_plural = "Photos"
I want to retrieve the last primary key from the database (postgresql) as below:
try:
last_inserted = Photos.objects.order_by('-id')[0]
print(last_inserted)
except IndexError:
print("No data in the database")
but instead of a primary key I always get a date from the date column which is really strange! printing the last_inserted gives me '2018-09-04'.
As a test I change the 'id' column to lang (does not exists in table) gives below error message:
Cannot resolve keyword 'lang' into field. Choices are: date, id, name, path, size
in the above message why date is coming first then id and so on ..!
please help!
print(last_inserted) will show you result of model's __str__ method. To see id you can change model:
class Photos(models.Model):
id = models.IntegerField(primary_key=True, default=1)
name = models.CharField(max_length=500)
size = models.IntegerField()
path = models.CharField(max_length=500)
date = models.DateField(default=datetime.now)
def __str__(self):
return str(self.id)
class Meta:
verbose_name_plural = "Photos"
Or just change query to select only id field using values_list:
last_inserted = Photos.objects.order_by('-id').values_list('id', flat=True)[0]
print(last_inserted)
As for
in the above message why date is coming first then id and so on ..!
I suppose it because of alphabetical order.
You can also try it like this. A bit shorter
Photos.objects.order_by('-id').first().id
There is also a last()

django views, getting request and using it as a parameter

I'm very confused about this right now,
so I know when there's a simple code like the below
def text_detail(request ,course_pk, step_pk):
step = get_object_or_404(Text, course_id = course_pk, pk=step_pk)
course_pk and step_pk from the url, and those requests are set equal to course_id and pk here. but what I don't understand is what is course_id and pk here? I mean, course_id is from Course model which is foreignkey to step. so it's self.Course.id so it's course_id. But then, how about the next one pk? shouldn't it be step_id = step_pk? when it's just pk how does django know which pk it is?
Sorry if the question is very confusing, I'm very confused right now.
Edit
class Step(models.Model):
title = models.CharField(max_length=200)
description = models.CharField()
order = models.IntegerField(default=0)
course = models.ForeignKey(Course)
class Meta:
abstract = True
ordering = ['order',]
def __str__(self):
self.title
class Text(Step):
content = models.TextField(blank=True, default="")
Actually the get_or_404() method doing a similar/exact job as below,
try:
return Text.object.get(pk=step_pk,course_id = course_pk)
except Text.DoesNotExist:
raise Http404
You can read the source code of the same here
What is course_id and pk ?
Both are attributes of your Text model, as the name indicates pk is your Primary Key of Text model and course_id is the id/pk of course field which is a FK.
EDIT
Text is inherited from Step model so, it will show properties of usual python class.Hence, the Text model be like this internally (not-exact)
class Text(models.Model):
content = models.TextField(blank=True, default="")
title = models.CharField(max_length=200)
description = models.CharField()
order = models.IntegerField(default=0)
course = models.ForeignKey(Course)
class Meta:
ordering = ['order', ]
def __str__(self):
return self.title
Example
text = Text.objects.get(id=1) # text instance with id=1
text.course_id # will hold the id of "course" instance which is related to the particular "text" instance
URL assignment and all those stuffs are entirely depends on your choice and logic. So If you need to get a Text instance in your view, do as below,
text = get_object_or_404(Text, pk = pk_of_TEXT_instance)

Python convert string to class

I want to do a query on the django User table like this:
u = User.objects.filter(member__in = member_list)
where:
class Member(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
dob = models.DateField('Date of Birth', blank=True, null=True)
and member_list is a list of eligible members.
The query works fine but the problem is I do not actually know the model member is called member. It could be called anything.
I store the name of the model I want in a model called Category. I have a link to the name of the model through content_type.Category is defined as:
class Category(models.Model):
name = models.CharField('Category', max_length=30)
content_type = models.ForeignKey(ContentType)
filter_condition = JSONField(default="{}", help_text=_(u"Django ORM compatible lookup kwargs which are used to get the list of objects."))
user_link = models.CharField(_(u"Link to User table"), max_length=64, help_text=_(u"Name of the model field which links to the User table. 'No-link' means this is the User table."), default="No-link")
def clean (self):
if self.user_link == "No-link":
if self.content_type.app_label == "auth" and self.content_type.model == "user":
pass
else:
raise ValidationError(
_("Must specify the field that links to the user table.")
)
else:
if not hasattr(apps.get_model(self.content_type.app_label, self.content_type.model), self.user_link):
raise ValidationError(
_("Must specify the field that links to the user table.")
)
def __unicode__(self):
return self.name
def _get_user_filter (self):
return str(self.content_type.app_label)+'.'+str(self.content_type.model)+'.'+str(self.user_link)+'__in'
def _get_filter(self):
# simplejson likes to put unicode objects as dictionary keys
# but keyword arguments must be str type
fc = {}
for k,v in self.filter_condition.iteritems():
fc.update({str(k): v})
return fc
def object_list(self):
return self.content_type.model_class()._default_manager.filter(**self._get_filter())
def object_count(self):
return self.object_list().count()
class Meta:
verbose_name = _("Category")
verbose_name_plural = _("Categories")
ordering = ('name',)
So I can retrieve the name of the model that links to User but I then need to convert it into a class which I can include in a query.
I can create an object x = category.content_type.model_class() which gives me <class 'cltc.models.Member'> but when I them perform a query s = User.objects.filter(x = c.category.object_list()) I get the error Cannot resolve keyword 'x' into field.
Any thoughts most welcome.
The left hand side of the filter argument is a keyword, not a python object, so x is treated as 'x', and Django expects a field called x.
To get around this, you can ensure that x is a string, and then use the python **kwarg syntax:
s = User.objects.filter(**{x: c.category.object_list()})
Thanks to https://stackoverflow.com/a/4720109/823020 for this.

Loop through objects and change their values

I have my model set up so that when a liquor is added to a store, it gives it it's own in-store ID based on the count. I've called this the SPI. The addition function works fine, it properly assigns the correct SPI. But I'm having trouble with the delete function. When an object is deleted from the table, I need it to loop through the remaining objects and set their SPI to one less. However I keep getting an error StoreLiquor matching query does not exist. Lookup parameters were {'StoreLiquorID': 7, 'storeID': <Store: test store>} Am I not doing the query correctly?
The models:
class Store(models.Model):
StoreID = models.AutoField(primary_key=True)
user = models.ManyToManyField(User)
StoreName = models.CharField('Store Name', max_length=30)
(other things here too but probably not necessary for this case)
class StoreLiquor(models.Model):
StoreLiquorID = models.AutoField(primary_key=True)
liquorID = models.ForeignKey(Liquor)
storeID = models.ForeignKey(Store)
StorePrice = models.DecimalField('Store Price', max_digits=5, decimal_places=2)
SPI = models.PositiveIntegerField('SPI', max_length=10)
The view:
def delete(request, liquor_id, store_id):
storeID = Store.objects.get(StoreID=store_id)
StLiquor = StoreLiquor.objects.get(storeID=store_id, StoreLiquorID=liquor_id)
LiqSPI = StLiquor.SPI
SPIcount = StoreLiquor.objects.filter(storeID=store_id).count()
for newSPI in range(LiqSPI, SPIcount):
newStLiquor = StoreLiquor.objects.get(storeID=storeID, StoreLiquorID=newSPI)
newStLiquor.SPI = newSPI-1
StLiquor.delete()
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
Instead of for loop, use queryset.update with django.db.models.F:
from django.db.models import F
...
StoreLiquor.objects.filter(storeID=storeID, SPI__gt=LiqSPI).update(SPI=F('SPI')-1)

Categories