How to use UUID - python

I am trying to get unique IDs for my Django objects. In Django 1.8 they have the UUIDField. I am unsure how to use this field in order to generate unique IDs for each object in my model.
Here is what I have for the UUIDField
import uuid
from django.db import models
class MyUUIDModel(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
class Person(models.Model):
...
unique_id = MyUUIDModel()
I can reproduce the id for the UUID model, but everytime I do I get the exact same id. For Example:
person = Person.objects.get(some_field = some_thing)
id = person.unique_id.id
id then gives me the same id every time. What is wrong, how do I fix this?

I'm not sure why you've created a UUID model. You can add the uuid field directly to the Person model.
class Person(models.Model):
unique_id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
Each person should then have a unique id. If you wanted the uuid to be the primary key, you would do:
class Person(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
Your current code hasn't added a field to the person. It has created a MyUUIDModel instance when you do MyUUIDModel(), and saved it as a class attribute. It doesn't make sense to do that, the MyUUIDModel will be created each time the models.py loads. If you really wanted to use the MyUUIDModel, you could use a ForeignKey. Then each person would link to a different MyUUIDModel instance.
class Person(models.Model):
...
unique_id = models.ForeignKey(MyUUIDModel, unique=True)
However, as I said earlier, the easiest approach is to add the UUID field directly to the person.

You need to use the class you created as a subclass when declaring your Person model like this:
import uuid
from django.db import models
class MyUUIDModel(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
class Person(MyUUIDModel):
...
This way Person becomes a subclass of MyUUIDModel and will inherit its id field definition.

EDIT: Actually I was wrong. It's not possible yet to implement it as DEFAULT_AUTO_FIELD as it has to inherit from IntegerField. Here's the ticket in the django project with feature request to make it possible. Once it's resolved I'll update my answer.
As of Django 3.2, if you want to use uuid as a pk for all your models on a project-wide level, you don't need a generic abstract model anymore. Just define DEFAULT_AUTO_FIELD setting
default value
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
so something like this should work
DEFAULT_AUTO_FIELD = 'django.db.models.UUIDField'
Or even better, create your own field.
DEFAULT_AUTO_FIELD = 'project.common.models.CustomUUIDField'
Where you also define uuid type etc.
As seen in the docs, it can also be applied on an app level.
class MyAppConfig(AppConfig):
default_auto_field = 'project.common.models.CustomUUIDField'

You can directly add the id field as a UUIDField in the Person model. There is no need for a separate MyUUIDModel.
I think you have confused it with the MyUUIDModel used in the UUIDField example where the id is a UUIDField. You can just use the below code and it will use UUIDs for id.
import uuid
from django.db import models
class Person(models.Model):
...
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

To use UUID in Django for a new model see Django Docs.
However, if you want to use it for the existing model (with unique=True) having data corresponding to it, you will not be able to do it directly by the above documentation. It will create migration errors.
To do it without losing the data follow all the steps carefully of this Django Documentation.

in model import uuid:
import uuid
in class model use:
class Article(TimeStampedModel):
uuid = models.UUIDField(editable=False, default=uuid.uuid4, unique=True)
user = models.ForeignKey(User, on_delete=models.SET_NULL, related_name='articles', null=True)
categories = models.ManyToManyField(ArticleCategory, blank=True)
title = models.CharField(max_length=500, null=True, blank=True)
body = RichTextUploadingField(config_name='portal_lobar_config')
image = models.ImageField(upload_to='article_images/', null=True, blank=True)
headline = models.BooleanField(default=True)
tags = models.ManyToManyField(ArticleTag, blank=True)
slug = AutoSlugField(max_length=500, populate_from='title', unique_with='created__month', null=True)
published = models.BooleanField(default=False)
published_at = models.DateTimeField(null=True, blank=True)
def __str__(self):
return self.title
class Meta:
ordering = ['-created']

Related

Django migrate primary key from UUID to Slug

I have model AAA with UUID as primary key. Many models have relation to this model.
Now I want to migrate them to use Slug as this primary key, to keep slug value in database as a reference.
What will be the correct way to do that?
Thinking that this might be some multi-step migration. But having many tables that reference to AAA would like to avoid blocking whole db for much time or any other issues in production.
from django.db import models
from django_extensions.db.fields import AutoSlugField
from model_utils.models import UUIDModel
# Django models example
class AAA(models.Model):
id = UUIDField(primary_key=True, version=4, editable=False)
title = models.CharField(max_length=255, unique=True)
slug = AutoSlugField(populate_from='title', primary_key=False)
class BBB(models.Model):
aaa = models.ForeignKey(AAA, on_delete=models.CASCADE)
# ... other fields here ...

one to many relationship not showing in admin

I was making a post system with two models Post and Image. I want one post to have multiple images
Here is my models
class Post(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
content = models.CharField(max_length=150, null=False)
images = models.ManyToOneRel(
field="image", to="Image", field_name="images")
class Image(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
image = models.ImageField()
post = models.ForeignKey(
Post, on_delete=models.CASCADE, related_name="images")
When I checked it in admin the images field is not shown.
I am not entirely sure how to use ManyToOneRel in django. So far what I understood is I need my post saved before i can add an image. Is there any other way I can have multiple images for one post
you only want one relation,in my opinion Foriegn key is better
Just try this:-
class Post(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
content = models.CharField(max_length=150, null=False)
image=models.ForeignKey(Image,on_delete=models.SET_NULL,null=True)
class Image(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
image = models.ImageField()
Note:- 'Foreign-key itself is a Many-To-One Relation'
You are confusing a relation with a model field. If you want to specify a many-to-one relation, you do that with a ForeignKey, not a ManyToOneRel. This should thus look like:
class Post(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
content = models.CharField(max_length=150, null=False)
image = models.ForeignKey(to='Image', on_delete=models.CASCADE)!
Likely you are however not interested in a many-to-one relation, but in a one-to-many relation (where one post can contain zero, one, or more Images). In that case the ForeignKey belongs to the Image model, and you thus set this when you create a new Image object in the ModelAdmin:

How should I give ForeignKey to model?

How should I give ForeignKey to model?
Now models.py has User&Item table like
from django.db import models
# Create your models here.
class User(models.Model):
user_id = models.CharField(max_length=200)
name_id = models.CharField(max_length=200)
regist_date = models.DateTimeField(auto_now=True)
class Item(models.Model):
user_id = models.CharField(max_length=200)
name = models.CharField(max_length=200)
item_name = models.CharField(max_length=200)
price = models.CharField(max_length=200)
I wanna treat user_id&name_id as Foreing key.User table is parent table,and Item is child one.I think user_id&name_id in Item should have ForeignKey like
class Item(models.Model):
user_id = models.ForeignKey()
name = models.ForeignKey()
However,how should I connect these 2 model is User is parent&Item is child ?How should I write it?
For sure, you have to read that.
Looks like One User -> Many Items.
Its ForeignKey and we have to set it in User model.
class Item(models.Model):
...
class User(models.Model):
...
item = models.ForeignKey(Item)
You can use something like
class Item(models.Model):
user = models.ForeignKey(User, related_name='items')
Accessing user_id from item will be
item.user.user_id
Accessing all items from a user will be
user.items.all()
It's a good idea to read the documentation on the ForeignKey field.
As for your question, you can connect the Item model to the User model like this:
class Item(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
Again, it's a good idea to read the documentation and figure out what exactly you need, such as what to do when a User object is deleted (the on_delete part in my code).

Django ManyToMany Field with an already existing table

What I'm trying to achieve is, having model Person that is created and managed by Django have a ManyToMany field with model Property that was "created" using inspectdb and already exists in the database.
(Property contains Geographical data and cannot be managed or changed by Django)
When trying to migrate, it raises :
ValueError: Related model 'cadastroapp.Property' cannot be resolved
Full stack here
Worth nothing that I removed from the migration file the step to create model Property, since it already exists and AFAIK there's no way to tell Django this in the model Class
models.py (simplified) :
class Person(models.Model):
objectid = models.AutoField(primary_key=True)
properties = models.ManyToManyField(
'Property',
through = 'Person_Property',
)
class Meta:
db_table = 'django_person'
class Person_Property(models.Model):
cod_person = models.ForeignKey('Person', on_delete=models.CASCADE)
cod_property = models.ForeignKey('Property', on_delete=models.CASCADE)
class Meta:
db_table = 'django_person_property'
class Property(models.Model):
objectid = models.BigIntegerField(unique=True, primary_key=True)
created_user = models.CharField(max_length=765, blank=True, null=True)
created_date = models.DateTimeField(blank=True, null=True)
last_edited_user = models.CharField(max_length=765, blank=True, null=True)
last_edited_date = models.DateTimeField(blank=True, null=True)
shape = models.TextField(blank=True, null=True) # This field type is a guess. - ESRI Shape
class Meta:
managed = False
db_table = '"GEO"."PROPERTY"'
There are a couple errors in your models.py file.
When defining a Foreignkey or ManytoMany field, you don't want the model name to be in quotes.
Please change:
class Person(models.Model):
properties = models.ManyToManyField(
'Property',
through = 'Person_Property',
)
and
class Person_Property(models.Model):
cod_person = models.ForeignKey('Person', on_delete=models.CASCADE)
cod_property = models.ForeignKey('Property', on_delete=models.CASCADE)
to:
class Person(models.Model):
properties = models.ManyToManyField(
Property,
through = 'Person_Property',
)
and
class Person_Property(models.Model):
cod_person = models.ForeignKey(Person, on_delete=models.CASCADE)
cod_property = models.ForeignKey(Property, on_delete=models.CASCADE)
then delete your migration file cadastroapp.0006_auto_20161122_1533.
then run makemigrations and migrate again.
This may still not migrate without errors, but it will get us on the right track.
I think that you want to put the model name in quotes. In case you leave it without quotes you have to ensure that the model is defined before the ManyToMany field has been defined. So you will need to have first class Property and then class Person in your file. When you put model name as "Property" then you do not need to care about order of class definitions.

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.)

Categories