Can I do the following to make a charfield unique and not null using tortoise orm?
class User(Model):
id = fields.IntField(pk = True)
username = fields.CharField(max_length = 128, unique = True, nullable = False)
Or what would be the appropriate field?
Is there a field for email type data? or which one should be used
Thank you!
The docs specify max_input and **kwargs as input parameters for CharField.
https://tortoise-orm.readthedocs.io/en/latest/fields.html#tortoise.fields.data.CharField
You can find the **kwargs for CharField in its parent class, the base Field.
https://tortoise-orm.readthedocs.io/en/latest/fields.html#tortoise.fields.base.Field
There you find parameters like:
null (bool) – Is this field nullable?
unique (bool) – Is this field unique?
validators (Optional[List[Union[Validator, Callable]]]) – Validators for this field.
See the docs for more info on how to use validators: https://tortoise-orm.readthedocs.io/en/latest/validators.html
Related
In my django model I would like to set the field unique_id below to be the primary key as this will be the field used in queries for the model. It satisfies unique=True and null=False. However as django sets an AutoField to primary key in the background I'm unsure whether a CharField (which uses a unique 3 character code) is suitable as a primary key or whether this will be sub-optimal?
class PaymentMethod(models.Model):
unique_id = models.CharField(max_length=3)
last_updated = models.DateTimeField(auto_now=True)
There is nothing wrong with setting the CharField to be a primary key, by changing the model to be:
class PaymentMethod(models.Model):
unique_id = models.CharField(max_length=3, primary_key=True)
last_updated = models.DateTimeField(auto_now=True)
In actual fact if the unique_id is the field you will be querying it makes perfect sense to use it. Your other options are to use your existing model but with unique=True:
class PaymentMethod(models.Model):
unique_id = models.CharField(max_length=3, unique=True)
last_updated = models.DateTimeField(auto_now=True)
In this case your primary key will be an auto incrementing integer as you previously stated.
Another option depending on the number of records you are looking to store in the PaymentMethod models; and where the data is used elsewhere within your application. Is too look into using a model choices field. The model choices field might be on your payments or order model (depends on your application and what you are trying to do). This removes the need for a foreignkey and potentially reduces the number of queries in your app.
It could look something like this:
class Payment(models.Model):
VISA = 'VIS'
CREDIT = 'CRE'
MASTER_CARD = 'MAS'
PAYPAL = 'PAL'
PAYMENT_OPTIONS= (
(VISA, 'Visa'),
(CREDIT, 'Credit Card'),
(MASTER_CARD, 'Master Card'),
(PAYPAL, 'Paypal')
)
items = models.ForeignKey(Item)
date = models.DateField(auto_now=True)
...
payment_method = models.CharField(max_length=3, choices=PAYMENT_OPTIONS, default=VISA)
The PAYMENT_OPTIONS can be used to render dropdown boxes on the forms when using django model forms. Otherwise the users selection is limited to the options listed within this model.
This method would be a lot more efficient if you only have a small subset of PaymentMethod(s).
It's possible to use CharField as primary key. You just have to mark the field as primary key.
field_name = models.CharField(primary_key=True, max_length=100)
But I wouldn't recommend it because:
Primary keys are used in urls (typically in Rest APIs) - but not all characters are allowed in urls
DRF (django-rest-framework) use urls patterns that don't catch some characters by default (for example ".")
Primary keys must be unique - it's harder to accomplish it if the field is a string, especially when you let users to define it
i have a model attribute having the following
class ph_no(models.Model):
phone_no = models.CharField(max_length = 20)
phone_no_assigned_to = models.CharField(max_length = 50)
actually the value for the field phone_no_assigned_to should come from many tables in db like
personal_usage
bussiness_usage etc..
Each of the willl have assigned to field
Also this phone_no_assigned_to can have mutiple values
Can anyone help me how to define it
You might want to define relationships, i.e. have a model phone_usage with usage types and link it to model's ph_no field phone_no_assigned_to. Or if "usage" is a small list of possible values use choices.
Have a look at:
https://docs.djangoproject.com/en/1.9/topics/db/models/#relationships
https://docs.djangoproject.com/en/1.9/topics/db/examples/
https://docs.djangoproject.com/en/1.9/ref/models/fields/#choices
Is it obligatory to specify all the propertis of a attribute like this
#Column(name = "ID_COMPANY", unique = true, nullable = false)
or make just :
#Column(name = "ID_COMPANY")
and for a string we have to specify a length ?
#Column(name = "NAME", length = 30)
or just :
#Column(name = "NAME")
Because if i change the length of varchar in my database i have to change it again at my mapping class and it's little hard if i have many changes.
No, it's not obligatory.
Most of these options other than name are used only if you use Hibernate to generate your database schema. If you maintain your schema manually, you can safely omit them.
However, some of them (such as nullable or unique) may be useful for documentation purposes.
All the elements of the #Column annotation have default values. Unless your schema goes against the defaults in nullability, uniqueness, length, etc. (or your DB column does not exactly match the name of your field name), you can leave them off the annotation to prevent clutter.
Defaults can be seen on the JavaDoc here: http://docs.oracle.com/javaee/7/api/javax/persistence/Column.html
As the question asks, is it necessary to have a numeric (and presumably, integer) value for a model's id? Or is any unique identifier acceptable? For example, could I use a GUID string?
It can be any arbitrary string according to the docs:
ID
A special property of models, the id is an arbitrary string (integer
id or UUID). If you set the id in the attributes hash, it will be
copied onto the model as a direct property. Models can be retrieved by
id from collections, and the id is used to generate model URLs by
default.
Yes you can. The backbone documentation states that "the id is an arbitrary string (integer id or UUID)".
An NDB model contains two properties: email and password. How to avoid adding to the database two records with the same email? NDB doesn't have UNIQUE option for a property, like relational databases do.
Checking that new email is not in the database before adding—won't satisfy me, because two parallel processes can both simultaneously do the checking and each add the same email.
I'm not sure that transactions can help here, I am under this impression after reading some of the manuals. Maybe the synchronous transactions? Does it mean one at a time?
Create the key of the entity by email, then use get_or_insert to check if exists.
Also read about keys , entities. and models
#ADD
key_a = ndb.Key(Person, email);
person = Person(key=key_a)
person.put()
#Insert unique
a = Person.get_or_insert(email)
or if you want to just check
#ADD
key_a = ndb.Key(Person, email);
person = Person(key=key_a)
person.put()
#Check if it's added
new_key_a =ndb.Key(Person, email);
a = new_key_a.get()
if a is not None:
return
Take care. Changing email will be really difficult (need to create new entry and copy all entries to new parent).
For that thing maybe you need to store the email, in another entity and have the User be the parent of that.
Another way is to use Transactions and check the email property. Transaction's work in the way: First that commits is the First that wins. A concept which means that if 2 users check for email only the first (lucky) one will succeed, thus your data will be consistent.
Maybe you are looking for the webapp2-authentication module, that can handle this for you. It can be imported like this import webapp2_extras.appengine.auth.models. Look here for a complete example.
I also ran into this problem, and the solution above didn't solve my problem:
making it a key was unacceptable in my case (i need the property to be changeable in the future)
using transactions on the email property doesn't work AFAIK (you can't do queries on non-key names inside transactions, so you can't check whether the e-mail already exists).
I ended up creating a separate model with no properties, and the unique property (email address) as the key name. In the main model, I store a reference to the email model (instead of storing the email as a string). Then, I can make 'change_email' a transaction that checks for uniqueness by looking up the email by key.
This is something that I've come across as well and I settled on a variation of #Remko's solution. My main issue with checking for an existing entity with the given email is a potential race condition like op stated. I added a separate model that uses an email address as the key and has a property that holds a token. By using get_or_insert, the returned entities token can be checked against the token passed in and if they match then the model was inserted.
import os
from google.appengine.ext import ndb
class UniqueEmail(ndb.Model):
token = ndb.StringProperty()
class User(ndb.Model):
email = ndb.KeyProperty(kind=UniqueEmail, required=True)
password = ndb.StringProperty(required=True)
def create_user(email, password):
token = os.urandom(24)
unique_email = UniqueEmail.get_or_insert(email,
token=token)
if token == unique_email.token:
# If the tokens match, that means a UniqueEmail entity
# was inserted by this process.
# Code to create User goes here.
# The tokens do not match, therefore the UniqueEmail entity
# was retrieved, so the email is already in use.
raise ValueError('That user already exists.')
I implemented a generic structure to control unique properties. This solution can be used for several kinds and properties. Besides, this solution is transparent for other developers, they use NDB methods put and delete as usual.
1) Kind UniqueCategory: a list of unique properties in order to group information. Example:
‘User.nickname’
2) Kind Unique: it contains the values of each unique property. The key is the own property value which you want to control of. I save the urlsafe of the main entity instead of the key or key.id() because is more practical and it doesn’t have problem with parent and it can be used for different kinds. Example:
parent: User.nickname
key: AVILLA
reference_urlsafe: ahdkZXZ-c3RhcnQtb3BlcmF0aW9uLWRldnINCxIEVXNlciIDMTIzDA (User key)
3) Kind User: for instance, I want to control unique values for email and nickname. I created a list called ‘uniqueness’ with the unique properties. I overwritten method put in transactional mode and I wrote the hook _post_delete_hook when one entity is deleted.
4) Exception ENotUniqueException: custom exception class raised when some value is duplicated.
5) Procedure check_uniqueness: check whether a value is duplicated.
6) Procedure delete_uniqueness: delete unique values when the main entity is deleted.
Any tips or improvement are welcome.
class UniqueCategory(ndb.Model):
# Key = [kind name].[property name]
class Unique(ndb.Model):
# Parent = UniqueCategory
# Key = property value
reference_urlsafe = ndb.StringProperty(required=True)
class ENotUniqueException(Exception):
def __init__(self, property_name):
super(ENotUniqueException, self).__init__('Property value {0} is duplicated'.format(property_name))
self. property_name = property_name
class User(ndb.Model):
# Key = Firebase UUID or automatically generated
firstName = ndb.StringProperty(required=True)
surname = ndb.StringProperty(required=True)
nickname = ndb.StringProperty(required=True)
email = ndb.StringProperty(required=True)
#ndb.transactional(xg=True)
def put(self):
result = super(User, self).put()
check_uniqueness (self)
return result
#classmethod
def _post_delete_hook(cls, key, future):
delete_uniqueness(key)
uniqueness = [nickname, email]
def check_uniqueness(entity):
def get_or_insert_unique_category(qualified_name):
unique_category_key = ndb.Key(UniqueCategory, qualified_name)
unique_category = unique_category_key.get()
if not unique_category:
unique_category = UniqueCategory(id=qualified_name)
unique_category.put()
return unique_category_key
def del_old_value(key, attribute_name, unique_category_key):
old_entity = key.get()
if old_entity:
old_value = getattr(old_entity, attribute_name)
if old_value != new_value:
unique_key = ndb.Key(Unique, old_value, parent=unique_category_key)
unique_key.delete()
# Main flow
for unique_attribute in entity.uniqueness:
attribute_name = unique_attribute._name
qualified_name = type(entity).__name__ + '.' + attribute_name
new_value = getattr(entity, attribute_name)
unique_category_key = get_or_insert_unique_category(qualified_name)
del_old_value(entity.key, attribute_name, unique_category_key)
unique = ndb.Key(Unique, new_value, parent=unique_category_key).get()
if unique is not None and unique.reference_urlsafe != entity.key.urlsafe():
raise ENotUniqueException(attribute_name)
else:
unique = Unique(parent=unique_category_key,
id=new_value,
reference_urlsafe=entity.key.urlsafe())
unique.put()
def delete_uniqueness(key):
list_of_keys = Unique.query(Unique.reference_urlsafe == key.urlsafe()).fetch(keys_only=True)
if list_of_keys:
ndb.delete_multi(list_of_keys)