Django official tutorial models part4 - python

I'm following djangoproject official tutorials in part 4 it use question.choice_set Statment I don't know what is mean choice_set can anyone help me?
Can I use question.Objects for example instead of question.choice_set?

If you make a ForeignKey from Choice to Question, like:
class Choice(models.Model):
# ...
question = models.ForeignKey(Question, on_delete=models.CASCADE)
Then Django automatically creates an opposite relation. By default, the name of the relation is nameofmodel_set.
Since there can be multiple Choice objects that map on the same Question, this is a set (a set that can contain zero, one, or more objects).
So by using somequestion.choice_set, you get an ObjectManager that deals with all the Choice objects for a specific Question instance (here the somequestion).
You can then for example .filter(..) on that set, or .update(..) or write custom ORM queries. So for example somequestion.choice_set.all() will give you all the related Choices.
Sometimes the name of this reverse relation is not very nice, in that case, you can use the reated_name parameter, to give it another name, like:
class Choice(models.Model):
# ...
question = models.ForeignKey(Question,
on_delete=models.CASCADE,
related_name='options')
In case you do not want such reverse relation (for example because it would result in a lot of confusion), then you can use a '+' as related_name:
class Choice(models.Model):
# ...
# no opposite relation
question = models.ForeignKey(Question,
on_delete=models.CASCADE,
related_name='+')

modelname_set is default attribute name by which you can access reverse related objects . So in your you have model something like:
class Question(Model):
...
class Choice(Model):
question = ForeignKey(Question)
...
So if you want to get all choices related to specific question you can use followng syntax:
question.choice_set.all()
You can change attribute name to something more human readable using related_name argument:
class Choice(Model):
question = ForeignKey(Question, related_name='choices')
In this case you can now use question.choices.all() to get question's choices.

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

Filter related model django

I am building the example django polls application. I want to exclude all polls, which have no choices. For that I have to access the related choices objects:
return Question.objects.filter(
pub_date__lte=timezone.now()
).exclude(
choice_set__count=0
).order_by('-pub_date')[:5]
But this query results in a field error:
Cannot resolve keyword 'choice_set' into field. Choices are: choice, id, pub_date, question_text
How can I query related models from the query?
To filter against a related model, you just use the lower-case model name - you can see that choice is one of the available fields.
However, this still won't work; there is no __count attribute to filter against. You can add one by using annotations, but there is a simpler way: compare against None:
.exclude(choice=None)
In the Choice model set the related_name to the Question foreign key.
Example:
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='choices')
# other code..
And then your query should be something like that:
return (Question.objects
.filter(pub_date__lte=timezone.now(),
choices__isnull=False)
.order_by('-pub_date')[:5])
Note: There is no `__count' lookup. If you want to rely on counts then check the docs on this.
docs: https://docs.djangoproject.com/en/1.10/ref/models/fields/#django.db.models.ForeignKey.related_name
The _set only applies when you are using that to retrieve the related model outside of the queryset, instead, as the error suggests, you can just use choice
.exclude(choice__isnull=True)

Understanding normalization tables in Django's ORM

I'm trying to learn Django from a background of coding the database schema directly myself. I want to understand how I should be effectively using the database abstraction tools to normalize.
As a contrived example, let's say I have a conversation that can ask questions on 3 subjects, and each question is complicated enough to warrant its own Class.
Class Conversation(models.Model):
partner = models.CharField()
Class Weather_q(models.Model):
#stuff
Class Health_q(models.Model):
#stuff
Class Family_q(models.Model):
#stuff
So let's say I want to have 2 conversations:
Conversation 1 with Bob: ask two different weather questions and one question about his health
Conversation 2 with Alice: ask about the weather and her family
Usually, I would code myself a normalization table for this:
INSERT INTO Conversation (partner) values ("Bob", "Alice"); --primary keys = 1 and 2
INSERT INTO NormalizationTable (fk_Conversation, fk_Weather_q, fk_Health_q, fk_Family_q) VALUES
(1,1,0,0), -- Bob weather#1
(1,2,0,0), -- Bob weather#2
(1,0,1,0), -- Bob health#1
(2,1,0,0), -- Alice weather#1
(2,0,0,1); -- Alice family#1
Do I need to explicitly create this normalization table or is that discouraged?
Class NormalizationTable(models.Model):
fk_Conversation = models.ForeignKey(Conversation)
fk_Weather_q = models.ForeignKey(Weather)
fk_Health_q = models.ForeignKey(Health)
fk_Family_q = models.ForeignKey(Family)
Then I then wanted to execute the conversations. I wrote a view like this (skipping exception catching and logic to iterate through multiple questions per conversation):
from myapp.models import Conversation, Weather_q, Health_q, Family_q
def converse(request):
#get this conversation's pk
#assuming "mypartner" is provided by the URL dispatcher
conversation = Conversation.objects.filter(partner=mypartner)[0]
#get the relevant row of the NormalizationTable
questions = NormalizationTable.objects.filter(fk_Conversation=conversation)[0]
for question in questions:
if question.fk_Weather_q:
return render("weather.html", Weather_q.objects.filter(pk=fk_Weather_q)[0])
if question.fk_Health_q:
return render("health.html", Health_q.objects.filter(pk=fk_Health_q)[0])
if question.fk_Family_q:
return render("family.html", Family_q.objects.filter(pk=fk_Family_q)[0])
Considered holistically, is this the "Django" way to solve this kind of normalization problem (N objects associated with a container object)? Can I make better use of Django's inbuilt ORM or other tools?
Leaving aside "normalization tables" (the term is unfamiliar to me), this is what I think is a "djangish" way of solving your problem. Please note that I went with your statement "each question is complicated enough to warrant its own Class". For me this means that every type of question necessitate its own unique fields and methods. Otherwise I would create a single Question model connected to a Category model by a ForeignKey.
class Partner(models.Model):
name = models.CharField()
class Question(models.Model):
# Fields and methods common to all kinds of questions
partner = models.ForeignKey(Partner)
label = models.CharField() # example field
class WeatherQuestion(Question):
# Fields and methods for weather questions only
class HealthQuestion(Question):
# Fields and methods for health questions only
class FamilyQuestion(Question):
# Fields and methods for family questions only
This way you would have a base Question model for all the fields and methods common to all questions, and a bunch of child models for describing different kinds of questions. There is an implicit relation between base model and its child models, maintained by Django. This gives you an ability to create a single queryset with different questions, no matter their type. Items in this queryset are of Question type by default, but can be converted to a particular question type by accessing a special attribute (for example a healthquestion attribute for HealtQuestions). This is described in detail in the "Multi-table model inheritance" section of Django documentation.
Then in a view you can get a list of (different types of) questions and then detect their particular type:
from myapp.models import Question
def converse(request, partner_id):
question = Question.objects.filter(partner=partner_id).first()
# Detect question type
question_type = "other"
question_obj = question
# in real life the list of types below would probably live in the settings
for current_type in ['weather', 'health', 'family']:
if hasattr(question, current_type + 'question'):
question_type = current_type
question_obj = getattr(question, current_type + 'question')
break
return render(
"questions/{}.html".format(question_type),
{'question': question_obj}
)
The code for detecting question type is quite ugly and complicated. You could make it much simpler and more generic using the InheritanceManager from django-model-utils package. You would need to install the package and add the line to the Question model:
objects = InheritanceManager()
Then the view would then look something like this:
from myapp.models import Question
def converse(request, partner_id):
question = Question.objects.filter(partner=partner_id).select_subclasses().first()
question_type = question._meta.object_name.lower()
return render(
"questions/{}.html".format(question_type),
{'question': question}
)
Both views select only a single question - the first one. That's how the view in your example behaved, so I went with it. You could easily convert those examples to return a list of questions (of different types).
I'm not familiar with the term normalization table, but I see what you're trying to do.
What you've described is not, in my opinion, a very satisfactory way to model a database. The simplest approach would be to make all questions part of the same table, with a "type" field, and maybe some other optional fields that vary between the types. In that case, this becomes very simple in Django.
But, OK, you said "let's say... each question is complicated enough to warrant its own class." Django does have a solution for that, which is generic relations. It would look something like this:
class ConversationQuestion(models.Model):
conversation = models.ForeignKey(Conversation)
content_type = models.ForeignKey(ContentType)
question_id = models.PositiveIntegerField()
question = GenericForeignKey('content_type', 'question_id')
# you can use prefetch_related("question") for efficiency
cqs = ConversationQuestion.objects.filter(conversation=conversation)
for cq in cqs:
# do something with the question
# you can look at the content_type if, as above, you need to choose
# a separate template for each type.
print(cq.question)
Because it's part of Django, you get some (but not total) support in terms of the admin, forms, etc.
Or you could do what you've done above, but, as you noticed, it's ugly and doesn't seem to capture the advantages of working with an ORM.

Setting up django model with user fields twice [duplicate]

I want to have two foreign keys to the same model:
class Test(models.model):
example1 = models.ForeignKey(Example)
example2 = models.ForeignKey(Example)
I get errors like:
Accessor for field 'example1' clashes with related
field 'Example.test_set'. Add a related_name argument
to the definition for 'example1'.
Try using related_name:
class Test(models.model):
example1 = models.ForeignKey('Example', related_name='example1')
example2 = models.ForeignKey('Example', related_name='example2')
Django uses some python magic to define relationships between models, some of which involves using the name of the models in the relationships (that's where the 'test' in 'test__set' is coming from.) What's happening, I would guess, is that it's trying to put "test__set" in the Example model twice, once for each foreign key you've got defined.
The error message suggests something to try: define a related_name argument (overriding one of those 'test_set's) that it can use instead of auto-generating two clashing names.
More info here: page has been removed
Current page relating to model relationships:
https://docs.djangoproject.com/en/2.0/ref/models/fields/#module-django.db.models.fields.related
Just do what the error message tells you to do, and if you're unsure what that means, consult the documentation for related_name.
In django 2.0 Try this:
user = models.ForeignKey(User, on_delete=models.PROTECT, null=True, related_name='user')
paper = models.ForeignKey(paperRecord, on_delete=models.PROTECT, null=True, related_name='paper')

Help a Python newbie with a Django model inheritance problem

I'm working on my first real Django project after years of PHP programming, and I am running into a problem with my models. First, I noticed that I was copying and pasting code between the models, and being a diligent OO programmer I decided to make a parent class that the other models could inherit from:
class Common(model.Model):
name = models.CharField(max_length=255)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.name
class Meta:
abstract=True
So far so good. Now all my other models extend "Common" and have names and dates like I want. However, I have a class for "Categories" were the name has to be unique. I assume there should be a relatively simple way for me to access the name attribute from Common and make it unique. However, the different methods I have tried to use have all failed. For example:
class Category(Common):
def __init__(self, *args, **kwargs):
self.name.unique=True
Causes the Django admin page to spit up the error "Caught an exception while rendering: 'Category' object has no attribute 'name'
Can someone point me in the right direction?
No, Django doesn't allow that.
See the docs: http://docs.djangoproject.com/en/1.1/topics/db/models/#field-name-hiding-is-not-permitted
Also answered in other questions like: In Django - Model Inheritance - Does it allow you to override a parent model's attribute?
You have a small mistake in your Common class
class Common(model.Model):
self.name = models.CharField(max_length=255)
should be
class Common(model.Model):
name = models.CharField(max_length=255)
Note that UNIQUE constraint in fact has nothing to do with Django, so you're free to add it in your database table. You can also use post-syncdb hook for that purpose.
Try using Meta.unique_together to force it into its own unique index. Failing that, it's probably easiest to create two separate abstract classes, one with the field unique and one not.

Categories

Resources