I have the following 3 tables
movies
ID | shortDesc | uploaded
sources
ID | name | createDate
movieSources
movieID | sourceID
How do I link them all together to get all the data in one REST call
I have the below code and it doesnt seem to work
models.py
class movieSources(models.Model):
class Meta:
db_table = "movieSources"
movieID = models.IntegerField()
sourceID = models.IntegerField()
class movies(models.Model):
class Meta:
db_table = 'movies'
uploaded = models.DateTimeField('date published')
sourcesMovie = models.OneToOneField(movieSources)
class sources(models.Model):
class Meta:
db_table = 'sources'
createDate = models.DateTimeField('date published')
Serializers.py
class MovieSourcesSerializer(serializers.ModelSerializer):
class Meta:
model = movieSources
fields = ('movieID', 'sourceID')
class MoviesSerializer(serializers.ModelSerializer):
sourceID = serializers.IntegerField(source='sourcesMovie.sourceID')
class Meta:
model = movies
fields = ('id','uploaded', 'sourceID')
First of all you have to rethink the design of your models. As described in the opening, there is a many-to-many relationship between movies and sources. movieSources would be the intermediate table, which isn't necessary to be declared as a model, as Django's ORM takes care about that.
Also I would suggest you to follow the conventions and write your model class names in PascalCase. Use rather singular names for this purpose.
models.py
class Movie(models.Model):
short_desc = models.CharField('short description', max_length=255)
uploaded = models.DateTimeField('date published', auto_now=True)
class Meta:
db_table = 'movies'
class Source(models.Model):
name = models.CharField(max_length=50)
create_date = models.DateTimeField('date published', auto_now=True)
movies = models.ManyToManyField(Movie, related_name='sources')
class Meta:
db_table = 'sources'
So should the models look like according to your description. The option auto_now=True will create automatically the timestamp when an entry is created. The models are connected with a m:n relation. Django takes care for everything else behind the doors.
Now you can create your serializers:
serializers.py
class MovieSerializer(serializers.ModelSerializer):
sources = serializers.PrimaryKeyRelatedField(many=True)
class Meta:
model = Movie
fields = (short_desc, uploaded, sources)
class SourceSerializer(serializers.ModelSerializer):
movies = serializers.PrimaryKeyRelatedField(many=True)
class Meta:
model = Source
fields = (name, create_date, movies)
The PrimaryKeyRelatedField will fetch the related data.
I didn't test the code and wrote it as I remember, but I think it should work out of the box. I hope the answer helps you and gives you an idea how to solve your problem better.
Related
I am looking to set up the backend logic for a form where it shoots information to a data table that I set up in postgresql and was wondering, how I would specify the data table that I want to send the information to?
You can do this with a ModelForm. Assuming the 'data table' you mention is the database model class, you declare the Model you are sending information to in the Meta class, as shown here:
class Author(models.Model):
name = models.CharField(max_length=100)
title = models.CharField(max_length=3, choices=TITLE_CHOICES)
birth_date = models.DateField(blank=True, null=True)
def __str__(self):
return self.name
class Book(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
class AuthorForm(ModelForm):
class Meta:
model = Author
fields = ['name', 'title', 'birth_date']
class BookForm(ModelForm):
class Meta:
model = Book
fields = ['name', 'authors']
Notice where it says "model = Book" or "model = Author". This example is from the Django Documentation on ModelForms. You will need to instantiate your ModelForm class in your view.
models.py
class Product(models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
price = models.DecimalField(decimal_places=5,max_digits= 1500)
summary = models.TextField()
featured = models.BooleanField()
def __str__(self):
return self.title
# return f'product title:{self.title}-product price:{self.price}'workok
class Meta:
ordering = ('-price',)
class Opinion(models.Model):
name = models.CharField(max_length=20)
email = models.EmailField(max_length=20)
body = models.TextField()
opinion_date = models.DateTimeField(auto_now_add=True)
active = models.BooleanField(default=False)
product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='opinion_set')
def __str__(self):
return f'({self.name}) add opinion about ({self.product})'
forms.py:
from django.forms import ModelForm
from .models import Product #space after from keyword
class OpinionModelForm(ModelForm):
class Meta:
model = Product
fields = ['name','email','body','product']
invalid in code line :
fields = ['name','email','body','product'] #---- NOT WORK !!!
, but if i change above code to :
fields = "__all__" # ----it is WORKing ok without any problem !!
question : what is the error? I am not need all the fields in the Product model (like active boolean field), I need only 'name','email','body','product' fields .
According to the error and the code you provided the main problem is that you made a mistake in chosing model in serializer:
class OpinionModelForm(ModelForm):
class Meta:
model = Product
fields = ['name','email','body','product']
Serializer name is OpinionModelForm and listed fields belong to Opinion so I guess you actually wanted to serialize Opinion and no Product as you defined at this line:
model = Product
Simply change it to:
model = Opinion
Preliminary note: this is a rather newbie question, though I have not found a sufficient answer on StackOverflow; many similar questions, but not this one. So I am asking a new question.
The problem: I'm having difficulty creating records where one field is a foreign key to an existing record, and I do not know what I'm doing wrong in my code.
In my app there are two models in question, a one-to-many relationship between Company and BalanceSheet:
models:
class Company(models.Model):
cik = models.IntegerField(default=0, unique=True)
symbol = models.CharField(max_length=4, unique=True)
name = models.CharField(max_length=255, unique=True)
def __str__(self):
return self.symbol
class BalanceSheet(models.Model):
company = models.ForeignKey(Company,
null=True,
on_delete=models.CASCADE,
related_name='balance_sheets',)
date = models.DateField()
profit = models.BigIntegerField()
loss = models.BigIntegerField()
class Meta:
unique_together = (('company', 'date'),)
def __str__(self):
return '%s - %s' % (self.company, self.date)
serializers:
class BalanceSheetSerializer(serializers.ModelSerializer):
company = serializers.StringRelatedField()
class Meta:
model = BalanceSheet
fields = ('company','date','profit','loss')
class CompanySerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = ('cik', 'symbol', 'name')
Views:
class BalanceSheetCreate(generics.CreateAPIView):
model = BalanceSheet
queryset = BalanceSheet.objects.all()
serializer_class = BalanceSheetSerializer
urls include:
url(r'^(?P<symbol>[A-Z]{1,4})/create-balance-sheet/$', views.BalanceSheetCreate.as_view(),
name='create_balance_sheet'),
To this point, I have zero problem reading data. However, when trying to create records, I get errors I don't understand:
curl http://localhost:8000/financials/AAPL/create-balance-sheet/ -X POST -d "company=AAPL&date=1968-04-17&profit=1&loss=1"
IntegrityError at /financials/AAPL/create-balance-sheet/
null value in column "company_id" violates not-null constraint
Dropping the company data from that curl command results in the same error.
How do I get around this error? I thought I was telling the api what company I'm interested in, both explicitly in the url and in the post data.
Using python3.6, django 1.11, and djangorestframework 3.7.7
You get the IntegrityError because your code will try to create a new BalanceSheet without a company. That's because StringRelatedField is read-only (see docs) and therefore it's not parsed when BalanceSheetSerializer is used in write mode.
SlugRelatedField is what you need here:
class BalanceSheetSerializer(serializers.ModelSerializer):
company = serializers.SlugRelatedField(slug_field='symbol')
class Meta:
model = BalanceSheet
fields = ('company','date','profit','loss')
To answer my own question, here's what I wound up with. Thanks again go to dukebody.
models:
class Company(models.Model):
cik = models.IntegerField(default=0)
symbol = models.CharField(max_length=4)
name = models.CharField(max_length=255)
def __str__(self):
return self.symbol
class BalanceSheet(models.Model):
company = models.ForeignKey(Company,
null=True,
on_delete=models.CASCADE,
related_name='balance_sheets',)
date = models.DateField()
profit = models.BigIntegerField()
loss = models.BigIntegerField()
class Meta:
unique_together = (('company', 'date'),)
def __str__(self):
return '%s - %s' % (self.company, self.date)
serializers:
class CompanySerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = ('cik', 'symbol', 'name')
class BalanceSheetSerializer(serializers.ModelSerializer):
company = CompanySerializer(many=False)
class Meta:
model = BalanceSheet
fields = ('company', 'date', 'profit', 'loss')
def create(self, validated_data):
company_data = validated_data['company']
company, created = Company.objects.get_or_create(**company_data)
validated_data['company'] = company
sheet = BalanceSheet.objects.create(**validated_data)
return sheet
I also had to include the full company data within my curl statement as a nested dict.
i am developing a rest API using django rest framework and i am stuck at a serializer the idea is to serialize a self recursive many to many model using a through table my code is:
model.py:
class Patient(models.Model):
class Meta:
db_table = 'patients'
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True)
id_card = models.CharField(max_length=45)
dob = models.DateField()
gender = EnumChoiceField(enum_class=Gender)
patientscol = models.CharField(max_length=45)
fk_user = models.ForeignKey(Users, related_name='user_patient', on_delete=models.CASCADE)
relative = models.ManyToManyField("self", through='PatientHasRelative')
class PatientHasRelative(models.Model):
class Meta:
db_table = 'patients_has_relatives'
fk_patient = models.ForeignKey(Patient, related_name='patient_has', on_delete=models.CASCADE)
fk_relative_patient = models.ForeignKey(Patient, related_name='patient_relative', on_delete=models.CASCADE)
relationship = EnumChoiceField(enum_class=Relationship)
my serializer.py is:
class PatientSerializer(serializers.ModelSerializer):
class Meta:
model = Patient
fields = ('__all__')
id = serializers.UUIDField(read_only=True)
id_card = serializers.CharField(required=True, max_length=45)
dob = serializers.DateField(required=True)
gender = EnumChoiceField(enum_class=Gender)
fk_user = serializers.PrimaryKeyRelatedField(required=True, queryset=Users.objects.all())
relative = PatientSerializer(read_only=True, required=True)#problem is here i cant use PatientSerializer here
class PatientHasRelativeSerializer(serializers.ModelSerializer):
class Meta:
model = PatientHasRelative
fields = ('__all__')
fk_patient = serializers.PrimaryKeyRelatedField(required=True, queryset=Patient.objects.all())
fk_relative_patient = serializers.PrimaryKeyRelatedField(required=True, queryset=Patient.objects.all())
relationship = EnumChoiceField(enum_class=Relationship)
a little help would be appreciated
To accomplish this you need to define related_name in the source model on the source field ie add
class Patient(models.Model):
relatives = models.ManyToManyField(
"self", through='PatientHasRelative', related_name='patients')
with this related_name you can easily access -- add/delete/set relatives/patients on either side of the relationships in the serializers
You can either do this using intermediary model
relative = Patient(**key_value_fields)
patient = Patient(**key_value_field)
PatientHasRelative.objects.create(
relative=relative, patient=patient, through_defaults=(relationship ='value',))
or you can do this
relative.patients.add(patient, through_defaults=relationship ='value')
or this
patient.relatives.add(relative, through_defaults=relationship ='value')
example retrieving
patient.relatives.all()
I have the following models:
class Category(models.Model):
name = models.CharField()
... # fields omitted
class Prediction(models.Model):
conversation = models.ForeignKey(Conversation)
category = models.ForeignKey(Category)
... # fields omitted
class Conversation(models.Model):
sid = models.CharField()
... # fields omitted
Now I'm trying to create a model serializer for Category that would return me the following serialized object:
{
"name":"blah",
"conversations":[
"2af22188c5c97256", # This is the value of the sid field
"073aef6aad0883f8",
"5d3dc73fc8cf34be",
]
}
Here is what I have in my serializer:
class CategorySerializer(serializers.ModelSerializer):
conversations = serializers.SlugRelatedField(many=True,
read_only=True,
source="prediction_set",
slug_field='conversation.sid')
class Meta:
model = models.Class
fields = ('class_name', 'conversations')
However, this doesn't work because somehow django doesn't allow me to set slug_field to be a field that's within an object field. Any suggestions on how to accomplish this?
You are modelling a Many-to-Many relationship between Categorys and Conversations with a explicit table called Prediction. The django way of doing this would be to explicitly state the Many-to-Many on either side of the relationship and specify Prediction as the "through-model":
Shamelessly stolen example from this question:
class Category(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField(unique=True, max_length=255, blank=True,default=None)
desc = models.TextField(blank=True, null=True )
...
class Post(models.Model):
title = models.CharField(max_length=255)
pub_date = models.DateTimeField(editable=False,blank=True)
author = models.ForeignKey(User, null=True, blank=True)
categories = models.ManyToManyField(Category, blank=True, through='CatToPost')
...
class CatToPost(models.Model):
post = models.ForeignKey(Post)
category = models.ForeignKey(Category)
...
This shows a good way to set up the relationship.
Equally shamelessly stolen from the answer by #Amir Masnouri:
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ('name','slug')
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ('id','{anything you want}','categories')
depth = 2
This shows a nice way of achieving the nested serialization behavior that you would like.