I want to make Django Model fields unique with two fields(values) in some conditions.
there's two fields: 'team', 'type'. And I want to make team manager unique
For Example:
team=1, type='manager'
team=1, type='manager'
-> Not available
team=1, type='manager'
team=1, type='member'
team=1, type='member'
team=2, type='manager'
-> Available
I think unique_together('team', 'type') won't work properly with this situation.
How can I make this with Django Model?
Here's my model below:
class myModel(models.Model):
team = models.ForeignKey('Team', on_delete=models.CASCADE)
type = models.CharField(max_length=10, default='member')
class Meta:
db_table = 'my_models'
I think, You need to use UniqueConstraint for your application which work perfect in kind of situation.
class myModel(models.Model):
team = models.ForeignKey('Team', on_delete=models.CASCADE)
type = models.CharField(max_length=10, default='member')
class Meta:
db_table = 'my_models'
constraints = [
models.UniqueConstraint(fields=['team', 'type'], name='unique_team')
]
you can also refer this link for more understanding. and let me know if following solution will work.
Given that there is a deprecation warning in the documentation (based on 3.2 docs) for unique_together, I think it's worth showing that this can be done using UniqueConstraint. I believe that the key missing ingredient from the previous answer is the use of UniqueConstraint.condition, like so:
from django.db import models
from django.db.models import Q, UniqueConstraint
class myModel(models.Model):
team = models.ForeignKey('Team', on_delete=models.CASCADE)
type = models.CharField(max_length=10, default='member')
class Meta:
db_table = 'my_models'
constraints = [
UniqueConstraint(
fields=['team', 'type'],
name='unique_team',
condition=Q(type='manager')
)
]
Related
I have tried to implement constraints for UniqueConstraint for two foreign keys in the Django model. So far it has not been working as expected. Here below is the model definition :
class AssetMember(models.Model):
asset = models.ForeignKey(Asset, null=True, related_name='assetmember_asset', on_delete=models.CASCADE)
project = models.ForeignKey(Project, null=True, related_name='assetmember_project', on_delete=models.DO_NOTHING)
class Meta:
constraints = [
models.UniqueConstraint(fields=["asset", "project"], name="assetmember_unique_object")
]
Yet, when I try to create two assetmember objects with the same asset and project as foreign key, I can see that the constraints are not working as expected :
How shall I implement the model and the UniqueConstraint, so that it will not create the same object with asset and project twice?
I have two models: Account and Transfer.
The model Account has the attribute currency (EUR, USD, JPY, etc.).
The model Transfer has two attributes account_from and account_to.
I want to add a constraint that checks that account_from uses the same currency as account_to.
I was thinking of adding such a constraint on Transfer model:
class Meta:
constraints = [
CheckConstraint(check=Q(account_from__currency=F('account_to__currency')), name='same_currency'),
]
But that doesn't work because of error
django.core.exceptions.FieldError: Joined field references are not permitted in this query
How do I do that ? Without relying on SQL. I know how to do that in SQL but I want to use the ORM. Or is it impossible to do that with Django ORM ?
Here are the two models (simplified to avoid noise):
class Tranfer(AuditedModel):
"""
The action of moving money from one account to another
"""
account_from = models.ForeignKey(Account, related_name="outgoing", on_delete=models.CASCADE)
account_to = models.ForeignKey(Account, related_name="incoming", on_delete=models.CASCADE)
class Account(AuditedModel):
"""
Recipient for money
"""
currency = models.CharField('currency', max_length=3, choices=(('EUR', 'Euro'), ('USD', 'American Dollars'), ('JPY', 'Japan Yen')))
class Meta:
constraints = [
CheckConstraint(check=Q(account_from__currency=F('account_to__currency')), name='same_currency'),
]
Follow the following steps for the solution of your problem.
The constrain section should be in the Transfer Model not in Account model.
Check constrain for any two relational model must be avoided.
The alternative for CheckConstraint() in the Constraint array of Meta section use the function clean for validation rather than constraint.
from django.db import models
from django.core.exceptions import ValidationError
class Account(models.AuditedModel):
"""
Recipient for money
"""
currency = models.CharField('currency', max_length=3, choices=(
('EUR', 'Euro'),
('USD', 'American Dollars'),
('JPY', 'Japan Yen')
))
class Transfer(models.AuditedModel):
"""
The action of moving money from one account to another
"""
account_from = models.ForeignKey(Account, related_name="outgoing", on_delete=models.CASCADE)
account_to = models.ForeignKey(Account, related_name="incoming", on_delete=models.CASCADE)
def clean(self):
if self.account_from.currency != self.account_to.currency:
raise ValidationError("Same currency required for transaction.")
return super().clean()
I don't understand this error on my model. My model (django 1.5.4):
from django.db.models import Model
from django.db import models
from django.utils.translation import ugettext_lazy as _
class ProductFactory(Model):
name = models.CharField(_(u"Name"), max_length=128)
products = models.ManyToManyField('Product', through='ProductFactoryProduct', related_name='factory')
components = models.ManyToManyField('Product', through='ProductFactoryComponent', related_name='factory')
class ProductFactoryProduct(Model):
factory = models.ForeignKey('ProductFactory')
product = models.ForeignKey('Product')
quantity = models.IntegerField(_(u"Quantity"), default=1)
class ProductFactoryComponent(Model):
factory = models.ForeignKey('ProductFactory')
product = models.ForeignKey('Product')
quantity = models.IntegerField(_(u"Quantity"), default=1)
class Product(Model):
active = models.BooleanField(_(u"Active"), default=True)
barcode = models.CharField(_(u"Barcode"), max_length=32, blank=True, null=True)
[...] # Nothing about factory
When i try to get Factory.products or Factory.components:
factory = ProductFactory.objects.get(pk=factory_id)
factory.products.all()
This error is throwed:
FieldError at /stock/factory/view/1
Cannot resolve keyword 'factory' into field. Choices are: active,
article, barcode, brand, categorys, code, comsumtion_type, id, name,
packaging, productreference, provider, providers, purchase_quantity,
quantity, quantity_with_ampute, stock_limit, stockmovement,
stockmovementproduct, work_unit
Note: active, article, barcode [...] fields are Product entity fields.
I don't understand why django is trying to use factory key on Product entity instead on ProductFactoryProduct entity. My model is wrong ? What is the problem ?
Edit: Full code: http://pastebin.com/SaMMUjd6
In class ProductFactory(Model): products and components have the same related_name (related_name='factory')
Try to change one.
I have to models connected by a ForeignKey
class User(AbstractUser):
...
and
class PrivateMessage(models.Model):
user_from = models.ForeignKey(
User,
verbose_name=u'From',
related_name='sent_messages',
)
user_to = models.ForeignKey(
User,
verbose_name=u'To',
related_name='received_messages',
)
Is there any way to get all the addresses for a particular user. For example, if
u = User.objects.get(id=1)
messages = PrivateMessage.objects.filter(user_from=u)
for m in messages:
users.add(m.user_to)
How to obtain a list of users that appear in user_to for these messages using only Django ORM methods?
I think a better idea would be to define ManyToManyField on the User model:
class User(AbstractUser):
#...
receivers = models.ManyToManyField('self', through='Message',
symmetrical=False, related_name="senders")
class Message(models.Model):
user_from = models.ForeignKey(MyUser, related_name='messages_from')
user_to = models.ForeignKey(MyUser, related_name='messages_to')
message = models.CharField(max_length=100, default="")
#...
Then to retrieve users list on the other end you simply do:
User.objects.get(id=1).receivers.all() # who I sent the message to
User.objects.get(id=1).senders.all() # who sent me a message
This way you have a nice clear API.
Finally, I ended up writing three queries:
users_from = set(PrivateMessage.objects.filter(
user_to=self.request.user,
).values_list(
'user_from__pk',
flat=True,
))
users_to = set(PrivateMessage.objects.filter(
user_from=self.request.user,
).values_list(
'user_to__pk',
flat=True,
))
interlocutors = User.objects.filter(pk__in=users_from.union(users_to))
I saw this docs
Maybe you can try:
u = User.objects.get(id=1)
users = User.objects.filter(received_messages__user_from=u).distinct()
related_name field makes our queries especially the ones using foreign key (on to many relation) easier, shorter and cleaner.
Let say we have 2 models classes Library and Book.
class Library(Models.model):
name = models.CharField(max_length = 100)
`class Book(Models.model):
title = models.CharField(max_length = 100)
library = models.ForeignKey(Library,
on_delete = models.CASCADE,
related_name = 'books')`
Here we have a one to many relation from Library to Book using foriegn key.
And in my django shell. I can create a new Library and a book related to that library in the following manner.
`from <app_name>.models import *`
`library = Library.objects.create(name = 'Big Library')`
`Book.objects.create(title = 'Awesome book', library = library`
Now I can query the book of the library using related name of model Book class:
`library.books.all()`
rather than using the starting the query from Book model as:
Book.objects.filter(library = library)
Imagine this model:
class ExercisePart(models.Model):
exercise = models.ForeignKey(Exercise)
sequence = models.IntegerField()
class Meta:
unique_together = (('exercise', 'sequence',),)
class Exercise(models.Model):
name = models.CharField(max_length=15)
From the admin interface I'd like to be able to create/link ExerciseParts through the Exercise page. I'd like to do that because I wish to avoid having to go on another page each time I want to add an ExerciseParts.
Is it possible ? How can I do that ?
You're looking for the inline admin feature.
admin.py
class ExercisePartInline(admin.TabularInline):
model = ExercisePart
class ExerciseAdmin(admin.ModelAdmin):
inlines = [ExercisePartInline]