Django: Specific unique_together condition - python

I have a model Article:
class Article(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(User, on_delete=models.SET(get_sentinel_user))
class Meta:
unique_together = ('author', 'title')
The method get_sentinel_user:
def get_sentinel_user():
return get_user_model().objects.get_or_create(username='deleted')[0]
Thus, using on_delete=models.SET(get_sentinel_user), I save posts after deleting the author (if he agrees to this, I ask him in a separate form). And instead of a real author, I set a "stub"-user as the author for his posts.
In such a situation, there is a problem with the uniqueness condition. If two users had articles with the same title and then one of them was deleted, then an error will occur when trying to delete the second user. Accordingly, I would like this error to be absent. So that the uniqueness condition applies only to real users and their articles. I tried this:
class Meta:
constraints = [
models.UniqueConstraint(
name='unique_combiantion_article_name_and_author',
fields=['title', 'author'],
condition=~models.Q(author__username='deleted')
)
]
But then I made sure that this does not work, we cannot use author__username.
Right now I'm thinking about just overriding validate_unique method. But first I would like to ask for advice. Maybe there is some other solution for this problem.
Thanks for any help.

Related

filter django queryset by onetoone model field property

i have two model classes and they are related by OneToOneField like here
class Book(models.Model):
is_user_ok = models.BooleanFiled()
class Mybook(models.Model):
book = models.OneToOneField( Book, related_name="Book", null=True, blank=True, on_delete=models.SET_NULL)
now i want make a queryset filter by book field property. but here book.is_user_ok
cannot be used. how can i make this queryset filter?
queryset = Mybook.objects.filter(book.is_user_ok=True)
You are looking a common problem, what you really want to do is related_name__column_name in filter, in your case you can try
queryset = Mybook.objects.filter(book__is_user_ok=True=True)
Reference from official docs:
https://docs.djangoproject.com/en/4.0/topics/db/queries/
double underscore is used for joins as you have already set the relationship in model variety of joins work here, it is used as per the model relation.
You are using a wrong syntax. Replace (book.is_user_ok=True) with (book__is_user_ok=True) The problem is, using '.' instead of '__'. Thats the correct syntax when dealing with another model class

the use of the underscore : q.choice_set.all()

I am working on the Django
Writing your first Django app, part 2
In the section "2.4.4 Playing with the API".
If someone could explain to me how does the underscore works in this code q.choice_set.all()
It's pretty simple. Let's consider these two models:
class Author(models.Model):
name = models.Charfield(max_lenght=100)
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
name = models.Charfield(max_lenght=100)
Explain:
We have some Authors that each author has some books.
but what if we want to get all books of a specific author?
let's assume we want all books that written by Sara:
my_author = Author.objects.get(name='Sara')
Here is the magic! Django will automatically generate the backward relation for this object called book_set which contains all books writen by Sara.
The naming rule is straightforward, <related_model_name>_set.
So, you can get those books by writing this line:
sara_books = my_author.book_set.all()
It's nice, isn't it ? wait, it could be nicer!
book_set is not a good name for me, i want a more human readable name!
you can easily change this by adding related_name to the author field of Book model:
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='her_books') # you can name it anything you want
name = models.Charfield(max_lenght=100)
then, you can get same books like this:
sara_books = my_author.her_books.all()
it's now more human readable :) Hope you get it.

The model has two many-to-many relations through the intermediate model

I have a model that has 2 separate ManyToManyField relations back to itself
class Company(models.Model):
parent = models.ManyToManyField("self", through='CompanyParent', through_fields=('company_child', 'company_parent'), related_name='+')
child = models.ManyToManyField("self", through='CompanyParent', through_fields=('company_parent', 'company_child'), related_name='+')
The above works fine on my localhost Django v3.0.2/ SQLite 3.8.7.2
To actually publish it, I have had to use Django v2.1.15/ SQLite 3.7.17, but with the published version it is chucking out the following errors
companies.Company.child: (fields.E332) Many-to-many fields with
intermediate tables must not be symmetrical.
companies.Company.parent: (fields.E332) Many-to-many fields with
intermediate tables must not be symmetrical.
companies.Company: (models.E003) The model has two many-to-many
relations through the intermediate model 'companies.CompanyParent'.
What's going on here? Solved the first 2 issues by adding symmetrical=False to each model, but no idea how to solve the final error?
You can check this answer to set up two many-to-many relations.
An example from the mentioned answer:
class Person(models.Model):
name = models.CharField(max_length=127, blank=False)
to_users = models.ManyToManyField(
'self',
symmetrical=False,
related_name='from_users',
through='Event',
through_fields=('from_user', 'to_user'),
)
class Event(models.Model):
item = models.ForeignKey(Item, related_name='events')
from_user = models.ForeignKey(Person, related_name='events_as_giver')
to_user = models.ForeignKey(Person, related_name='events_as_receiver')
In the event anyone happens across the same issue; the above is the answer but thought I would expand slightly after making the necessary changes to my own project
If you are looking to have numerous many-to-many within the same model and if you are on a version of Django after 2.2a1, then the best method is the one detailed in my question; two different models which you can easily call on views or templates; for example -
> data.manytomany1
> data.manytomany2
However, before 2.2a1 you will have issues. For me, this is because on cPanel, I have to use Django v2.1.15 due to the older SQLite 3.7.17 utilised. This means that you can only have one ManyToManyField (see above) and use a filter to get your 2nd manytomany > you will only be able to do this in the views.py
Hope that makes sense

Django: Use other model classes as choices for a field

I'm writing a Django app that includes a poll section, and I want to offer the ability to create different types of questions. So, I have these models for the rating part
# Do I really need this class?
class BaseRating(models.Model):
class Meta:
abstract = True
# For questions like: "Rate your experience with XXXXX"
class FiveStarRating(BaseRating):
rating = models.PositiveSmallIntegerField(null=True, blank=True, validators=[MaxValueValidator(5)])
# For questions like: "Would you recommend XXXXX"?
class YesNoRating(BaseRating):
rating = models.BooleanField()
I now want to create a new question, and I want to specify the rating system for it:
If I create the question "How would you rate xxxxx", I'd use FiveStarRating model
If I create the question "Are you satisfied with xxxx", I'd use YesNoRating
So, how should I design the question model?
class Question(models.Model):
title = models.CharField(max_length=255)
# rating??
# I can't create a foreignkey field to the base class...
EDIT: I am finally using django-dynamic-forms, but I consider the first response as an acceptable one too
From what i can see, you're not using the BaseRating model for anything, so it's safe to remove it.
As for the questions, in my case, i'll create two new models that have foreign keys to both FiveStarRating and YesNoRating so the data can be exclusive from each other. so you'll end up having two models like this.
class FiveStarQuestion(models.Model):
title = models.CharField(max_length=255)
rating = fields.ForeignKey(FiveStarRating)
class YesNoQuestion(models.Model):
title = models.CharField(max_length=255)
rating = fields.ForeignKey(YesNoRating)
but if you want to share the titles among the two questions (I would second this approach because there might be two questions with the same title)
Example:
How would you rate Stackoverflow
and
How Satisfied are you with Stackoverflow
It makes sense to have only one title called Stackoverflow and use that Reference as a foreignkey in our tables. So in this case, you can keep the Question model and have ForiegnKey fields that point to it.
class Question(models.Model):
title = models.CharField(max_length=255)
The create the two models as follows:
class FiveStarQuestion(models.Model):
title = models.ForeignKey(Question)
rating = fields.ForeignKey(FiveStarRating)
class YesNoQuestion(models.Model):
title = models.ForeignKey(Question)
rating = fields.ForeignKey(YesNoRating)

Django: Referencing a manytomany field that has been defined in another model

I'm trying to work out how to calculate the number of books written by an author. The book model sets up the manytomany field with the author model. I have no idea how even google something like this which I thought would be very simple to do but I don't even know how to start.
Here's the stripped down code:
class Author(models.Model):
first_name = models.CharField()
last_name = models.CharField()
def books(self):
"""Return a list of comma separated list of books by the author"""
pass
class Book(models.Model):
title = models.CharField()
authors = models.ManyToManyField(Author)
Maybe I could do a filter query to get books by a particular author but it doesn't seem like the django way to do it? I'm also not sure how to pass the filter function a python object rather than text.
Thanks
when you define a foreignkey or manytomany field, django sets up a reverse relation for you, which in your case is book_set. so something like:
def books(self):
books = self.book_set.all()
return ', '.join([book.title for book in books])
see related objects in the docs

Categories

Resources