Populate unique ID in Django Rest Framework - python

I am trying to make my ID in class Animal unique, so that it automatically increments without a user having to add data into the filed (so the filed is hidden), but I can't figure out how to do it.
Right now I have this in my models.py:
class Animal(models.Model):
id = models.CharField(max_length=100, blank=True, unique=True, default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=200)
Which in my mind will have to make id unique, but currently it doesn't do anything.
Here is my serialisers.py for reference:
class AnimalSerialiser(serializers.HyperlinkedModelSerializer):
doctor = DoctorSerealiser(read_only=True)
class Meta:
model = Animal
fields = ('id' , 'name' , 'gender' , 'breed' , 'adoption' , 'vaccines', 'doctor')

As other people have mentioned in the comments, you're defining your model wrong. Django adds an auto-incrementing field by default. Take a look at the docs for more information - https://docs.djangoproject.com/en/1.9/topics/db/models/#automatic-primary-key-fields.
You really just need:
class Animal(models.Model):
name = models.CharField(max_length=200)
and then you can still access that field like animal.id.
And UUID's are totally different than an auto-incrementing ID. See the wiki - they're basically just strings that are nearly impossible to generate duplicates of.

Related

Django Extend Model with Optional Fields

I have a django model that looks something like
class Person(models.Model):
name = models.CharField(max_length=100)
favorite_color = models.CharField(max_length=100)
favorite_candy = models.CharField(max_length=100)
and I want to make a template model for it. Basically, I want a model that can have an arbitrary amount of Person's fields filled out. For instance, say I wanted to have a template for Person that likes chocolate - I'd say something like chocolate_template = PersonTemplate(favorite_color='chocolate') and if I wanted someone whose name is Gerald, I could say gerald_template = PersonTemplate(name='Gerald'). The thought is that I could use these template objects to later pre-fill a Person creation form.
My main question is an implementation question. It's totally possible for me to make a template like so
class PersonTemplate(models.Model):
name = models.CharField(max_length=100, blank=True)
favorite_color = models.CharField(max_length=100, blank=True)
favorite_candy = models.CharField(max_length=100, blank=True)
but the code is horrible in that I have to manually copy-paste the contents of the Person class. This means that if I change Person, I have to remember to update PersonTemplate. I was wondering if there's a prettier way to make a 'child' of a model where all of the fields are optional. Setting all of the fields of Person to blank=True and adding an isTemplate field is also a no-no because Person and PersonTemplate should be two different entities in the database. Any thoughts on this?
Yes of course :)
class PersonTemplate(Person):
field = models.CharField(max_length=100, blank=True)
Its mean you have every fields from Person and you can add more specific fields for PersonTemplate
class Person(models.Model):
Already extend from Model, its why you have access to created, modified, id, pk....
What is good its PersonTemplate 'extend' Person who 'extend' Model.
Since Django 1.10 you can overrride field like that :
class PersonTemplate(Person):
favorite_color = models.CharField(max_length=100, blank=True)
favorite_candy = models.CharField(max_length=100, blank=True)

Django Foreign Key automatically filled based off of another field on model

So I currently have an "Account" Model and "Account Comments" Model -- keep in mind, that I can't really control the scheme of the database, and I'm writing a wrapper around existing DB.
Under the AccountComments Model, there is a field called "Data". It is where the AccountComments actually are and I'm trying to basically create a foreign key on the Account model without actually having to redesign and add a "AccountComments" field on Account that holds the AccountID.
class Account(models.Model):
AccountID = models.AutoField(editable=False, db_column='AccountID', verbose_name='ID',
primary_key=True)
acctno = models.IntegerField(editable=True, unique=True, db_column='ACCTNO', verbose_name='Acct #', blank=True,
null=True) # Field name made lowercase.
accountComments = models.ForeignKey('accountComments',to_field='accountID',db_column='Data')
def __str__(self):
return str(self.acctno)
class Meta:
managed = False
db_table = 'Account'
class accountComments(models.Model):
accountCommentID = models.AutoField(db_column='AccountCommentID', primary_key=True) # Field name made lowercase.
accountID = models.IntegerField(db_column='AccountID') # Field name made lowercase.
EntryUserID = models.IntegerField(db_column='EntryUserID') # Field name made lowercase.
EntryStamp = models.DateTimeField(db_column='EntryStamp', ) # Field name made lowercase.
Data = models.TextField(db_column='Data') # Field name made lowercase.
guid = models.CharField(db_column='guid', max_length=255) # Field name made lowercase.
class Meta:
managed = False
db_table = 'AccountComment'
ultimately, want accountComments on the Account Model to use 'AccountID' to do a lookup onto accountComments.accountID and then provide back 'Data'.
I know that I can use
def accountComments(self):
return str(accountComment.objects.get(accountID = self.AccountID).Data)
but I want it to work with Django Admin, so I need it to be an integrated part of the model.
Thanks if anyone can point me in the right direction.
You're trying to do too much with a foreign key. Following a foreign key in Django should return the model instance, not a particular field from the model instance.
The db_column should be the column in the Account table that stores the id, e.g.
accountComments = models.ForeignKey('accountComments',to_field='accountID',db_column='AccountID')
Then, to get the Data for a particular account instance, you would do:
account.accountComments.Data

Django reference a Model by foreign key or a different field

I am using Django REST Framework. I have two models, Sites and Statuses.
class Sites(models.Model):
site_id = models.AutoField(primary_key=True)
status = models.ForeignKey(Statuses, models.DO_NOTHING, blank=True, null=True)
class Statuses(models.Model):
status_id = models.AutoField(primary_key=True)
description = models.CharField(max_length=255, blank=True, null=True, unique=True)
class Meta:
managed = True
db_table = 'Statuses'
I would like to be able to perform a GET on sites, and have the Statuses.description field returned (instead of Statuses.status_id). Also, I would like it so that either status_id or description may be used interchangeably in a POST to create a new site. Where does this type of functionality belong (serializer, models, etc...)?
I know I can accomplish the first part of my question by adding a property to the Sites model and then referencing this field in the Sites serializer.
#property
def status(self):
return self.row_status.description
However I thought the convention of a Model is that it should be a 1:1 representation of the database table. Is there a better way to do this?
This fits well in the serializer, like this:
class SitesSerializer(serializers.ModelSerializer):
description = serializers.CharField(source='status.description')
class Meta:
model = Sites
fields = ('site_id', 'description')
(But the status field should probably not have null=True set.)

Validating admin site save in Django

I have the following two classes defined in models.py
class Part(models.Model):
name = models.CharField(max_length=32)
value = models.CharField(max_length=32)
class Car(models.Model):
name = models.CharField(max_length=32)
parts = models.ManyToManyField(Part)
So my model allows for multiple parts, but I want the part names to be unique. For example, only one part with name "engine" should be allowed for a given car. How do I enforce this uniqueness?
Things I have looked into:
class save()
Overriding the default save() for Car doesn't help because parts isn't updated until save is hit.
class save_model()
This will not work because it always saves.
So what are my options for enforcing uniqueness of part names?
UPDATED:
Although I want only one part with name engine to be associated with a car, I still want the ability to define multiple parts with name engine, of course with different values.
So a car with can have a part (part.name=Engine and part.value=V6) and another car can have a part (part.name=Engine and part.value=V4, but a car can't have two parts that have part.name == engine.
EDIT:
class Part(models.Model):
name = models.CharField(max_length=32)
value = models.CharField(max_length=32)
class CarPart(models.Model):
car = models.ForeignKey(Car)
part_type = models.CharField(max_length=32, unique=true)
part = models.ForeignKey(Part)
class Car(models.Model):
name = models.CharField(max_length=32)
treat part_type as part type id (e.g. type='engine') for engines it will be unique
more about ForeignKey

Retrieve Django rest framework related fields

Using the django-rest-framework is it possible to retrieve content from a related field. So for example I want to create a genre list which contains all projects within it. This is what I have but I keep on getting the error:
'Genre' object has no attribute 'project_set'
models.py
class Genre(models.Model):
name = models.CharField(max_length=100, db_index=True)
class Project(models.Model):
title = models.CharField(max_length=100, unique=True)
genres = models.ManyToManyField(Genre, related_name='genres')
serializers.py
class GenreSerializer(serializers.ModelSerializer):
project_set = serializers.ManyRelatedField()
class Meta:
model = Genre
fields = ('name', 'project_set')
The related name you're using on the Project class is badly named. That related name is how you access the set of projects related to a given genre instance. So you should be using something like related_name='projects'. (As it is you've got it the wrong way around.)
Then make sure that your serializer class matches up with the related name you're using, so in both places project_set should then instead be projects.
(Alternatively you could just remove the related_name='genres' entirely and everything will work as you were expecting, as the default related_name will be 'project_set'.)

Categories