NOT NULL constraint failed: product_product.author_id - python-3.x

When I am going to post objects in the postman I am getting this error
NOT NULL constraint failed: product_product.author_id
I included Basic Auth in the Authorization section anyway it gives me error.
models.py
class Product(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
name = models.CharField(max_length=200)
brand = models.CharField(max_length=200)
rating = models.PositiveSmallIntegerField(default=0)
description = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
serializers.py
class ProductSerializer(serializers.HyperlinkedModelSerializer):
category = serializers.SlugRelatedField(queryset=Category.objects.all(), slug_field='name')
author = serializers.ReadOnlyField(source='author.username')
class Meta:
model = Product
fields = ['id', 'url', 'category', 'name', 'brand', 'rating', 'description', 'price']
Why Not Null constraint happens? how can I solve this? Thanks in advance!

I think you should add models.create_all() in Models.py to create the database

The error happens simply because your create request is not providing a value for
author attribute of a product.
# models.py
class Product(models.Model):
....
author = models.ForeignKey(User, on_delete=models.CASCADE)
so in order to resolve this issue totally depends on your business logic,
Is it important for a product to have an Author?
[NO] ==> then just make the foreign key null=True, blank=True
[YES] ==> Then you need to modify your creation logic a lil bit.
Is the author of a product is the same one who created it?
[YES], then this can easily be done by overriding your serializer's create method
....
# Inside you serializer
def create(self, validated_data):
validated_data['author'] = self.context['request'].user
return super().create(validated_data)
[NO], You have to make the serializer accept writes on author field.
A small note, your ProductSerializer Meta class's fields attribute, doesn't include 'author', make sure it is added there too.

Related

Django model relations access

Are there any easy way of accessing all the article comments when I have setup my models like this? If this is not the correct way of doing it, please let me know a better way to create a relationship.
My model,
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Article(models.Model):
author = models.ForeignKey(User,on_delete=models.CASCADE)
title = models.CharField(max_length=100)
content = models.TextField()
def __str__(self):
return self.title
class Comment(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE)
author = models.ForeignKey(User, on_delete=models.CASCADE, default=True)
comment = models.CharField(max_length=450, blank=False, null=True)
def __str__(self):
return f"{self.comment}"
Are there any easy query to access the comment when looping the article? Or is this the wrong way of setting up relations?

Why some fields are not created while making migrations?

I have this two models in models.py
class Bid(models.Model):
bid = models.IntegerField(default = 0)
user = models.ForeignKey(User, on_delete = models.CASCADE, related_name = "bid")
def __str__(self):
return f"Bid of {self.bid} from {self.user}"
class AuctionListings(models.Model):
name_of_item = models.CharField(max_length=32)
description = models.CharField(max_length=400)
owner = models.ForeignKey(User, on_delete = models.CASCADE, related_name="auctionlistings", default = None)**
bid = models.ForeignKey(Bid, on_delete = models.CASCADE, related_name = "auctionlistings", default = None)**
is_closed = models.BooleanField(default=False, blank=True, null=True)
url = models.CharField(max_length=800)
watchlist = models.ManyToManyField(User, blank=True, related_name="watch_listings")
category = models.CharField(max_length=50)
When i makemigrations:
operations = [
migrations.CreateModel(
name='AuctionListings',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name_of_item', models.CharField(max_length=32)),
('description', models.CharField(max_length=400)),
('is_closed', models.BooleanField(blank=True, default=False, null=True)),
('url', models.CharField(max_length=800)),
('category', models.CharField(max_length=50)),
],
),
migrations.CreateModel(
name='Bid',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('bid', models.IntegerField(default=0)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='bid', to=settings.AUTH_USER_MODEL)),
],
),
My Question is: Why Django did not create the fields: "bid" and "user" specified in models.py.
The key to understand this behaviour is the method generate_created_models used when Django tries to figure out the operations needed when generating the migrations. In this method's docs we can read the following:
"""
Find all new models (both managed and unmanaged) and **make create
operations for them as well as separate operations to create any
foreign key or M2M relationships (these are optimized later, if
possible)**.
Defer any model options that refer to collections of fields that might
be deferred (e.g. unique_together, index_together).
"""
So for fields that refer to Foreign Keys or Many to Many relationships, Django will try to optimize the operations. The most common options are:
Include the field when creating the model with migrations.CreateModel (as you can see, you have an example in your code for the Bid.user field).
Create the model with migrations.CreateModel without the field. After the creation, Django adds each new field with migrations.AddField (this is what is happening to your AuctionListings.owner, AuctionListings.bid and AuctionListings.watchlist fields, which aren't included while calling migrations.CreateModel in your code).
All in all, an important thing to note is that fields are not created. Actually, models are created and this models contain fields, which can be specified during creation or added later.
With that into account, in your migrations file, just below the lines of code that you posted you should see some operations using migrations.AddField and account for the addition of the fields that are not included in migrations.CreateModel.

How to join two tables in django and serialize the same using one serializer?

I have been learning django and django rest framework since couple of weeks and I want to figure out how can I join two tables and serialize the data of same to return the json response using django rest framework.
I want to return result as json response:
{ 'user_id_id': 1, 'request_msg': 'Hi', 'response_msg': "Hi, Welcome" }
where result is
from django.db import connection
cursor = connection.cursor()
con = cursor.execute("SELECT backend_request_messages.user_id_id, backend_request_messages.request_msg as request_msg,backend_response_messages.response_msg as response_msg FROM backend_request_messages,backend_response_messages Where backend_request_messages.user_id_id=backend_response_messages.user_id_id=1 ")
Here is what I have tried :
#backend/Models.py
class User(models.Model):
username = models.CharField(max_length=50)
name = models.CharField(max_length=50, blank=True, null=True)
uid = models.CharField(max_length=12, blank=True, null=True)
age = models.CharField(max_length=3, blank=True, null=True)
active = models.BooleanField(default=True)
class Meta:
default_related_name = 'users'
def __str__(self):
return self.name
class Request_Messages(models.Model):
request_msg = models.CharField(max_length=100)
request_msg_created_at = models.DateTimeField(auto_now_add=True)
user_id = models.ForeignKey(
User, on_delete=models.CASCADE, null=True)
class Meta:
default_related_name = 'request_messages'
def __str__(self):
return self.request_msg
class Response_Messages(models.Model):
response_msg = response_msg = models.CharField(max_length=400)
response_msg_created_at = models.DateTimeField(auto_now_add=True)
user_id = models.ForeignKey(
User, on_delete=models.CASCADE, null=True)
class Meta:
default_related_name = 'response_messages'
def __str__(self):
return self.response_msg
#backend/serializers.py
class ListSerializer (serializers.Serializer):
user_id_id = serializers.IntegerField()
request_msg = serializers.CharField(max_length=100)
# request_msg_created_at = serializers.DateTimeField(read_only=True)
response_msg = serializers.CharField()
# response_msg_created_at = serializers.DateTimeField(read_only=True)
#backend/views.py
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Response_Messages, Request_Messages, User
from .serializers import ListSerializer
from django.db import connection
#api_view(['GET', 'POST'])
def chatbot(request):
if request.method == 'GET':
cursor = connection.cursor()
query_set = cursor.execute("SELECT backend_request_messages.user_id_id, backend_request_messages.request_msg as request_msg,backend_response_messages.response_msg as response_msg FROM backend_request_messages,backend_response_messages Where backend_request_messages.user_id_id=backend_response_messages.user_id_id=1 ")
columns = [column[0] for column in query_set.description]
results = []
for row in query_set.fetchall():
results.append(dict(zip(columns, row)))
serializer = ListSerializer(results)
return Response(serializer.data)
About serializers, You should refer to the docs (they're awesome and explain it best).
To give you a direction, I like to create a serializer for every model and if it's related to another model, I refer that in serializer, that way, You can easily customize behavior for each model (although not the only way at all).
So, about serializing I would do the following (notice my comments as well):
from django.contrib.auth.models import User
class User(User):
# Your user class, except, it should inherit Django's User/AbstractUser class.
class RequestMessages(models.Model):
request_msg = models.CharField(max_length=100)
request_msg_created_at = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(
User, on_delete=models.CASCADE, null=True, related_name='requests_msg')
# NOTICE THE NEW RELATED NAME, WE'LL USE IT LATER.
class Meta:
default_related_name = 'request_messages'
def __str__(self):
return self.request_msg
class ResponseMessages(models.Model):
response_msg = response_msg = models.CharField(max_length=400)
response_msg_created_at = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, related_name='responses_msg')
def __str__(self):
return self.response_msg
class RequestMsgSerializer(serializers.ModelSerializer):
# Specify what ever you like...
class Meta:
model = RequestMessages
fields = # Whatever you like to serialize.
class ResponseMsgSerializer(serializers.ModelSerializer):
class Meta:
model = ResponseMessages
fields = # Whatever you want serialized.
class UserSerializer(serializers.ModelSerializer):
# Using required = False will cause that every time you create a user they don't have to own messages.
requests_msg = RequestMsgSerializer(many=False, required=False)
responses_msg = ResponseMsgSerializer(many=False, required=False)
class Meta:
model = User
field = # Same as above ..
About your query, using raw SQL in Django is rear, usually, in most cases the Django built-in ORM will do the job and usually faster and better than you.
In your case, if you'll call your query like this for exmaple:
query_set = User.objects.filter(user=request.user)
the QuerySet object created will hit the DB one for the user object and X queries for all the associated messages with said user, so expensive.
But no need for a custom query with joins and stuff like that, Django has prefetch_related and select_related.
exmaple:
query_set = User.objects.filter(user=request.user).prefetch_related('requests_msg')
will reduce all the queries made for request messages associated to a user to only one!
Recap:
I wrote a lot because I'm still learning this stuff myself self and if you teach others you got it!
Refer to DRF's docs about serializers (there's even a dedicated section for nested serializers) and API Views, they really great.
Refer to Django's docs about prefetch related, select related and queries in general, again, Amazing docs that cover everything.
Don't just copy my code or anyone else's, there's no problem with that, just make sure you understand it first if not, you're bound to get stuck with it again!

how to convert this model into non editable model in admin of django?

I create a model but I need a non-editable model. When I visit the model it's just displaying text, not giving any option of update the record in admin panel.
model.py
class Contact(models.Model):
name = models.CharField(max_length=160)
email = models.EmailField()
subject = models.CharField(max_length=255)
message = models.TextField()
def __str__(self):
return self.subject
While searching I get information about readonly but I do not still understand how to use it.
There are two ways to do this. One, make editable=False for all the fields, then it will not be edible anywhere(modelform and adminsite):
class Contact(models.Model):
name = models.CharField(max_length=160, editable=False)
email = models.EmailField(editable=False)
subject = models.CharField(max_length=255, editable=False)
message = models.TextField(editable=False)
Two, in adminsite, use readonly_fields:
class ContactAdmin(admin.ModelAdmin):
readonly_fields = ('name', 'email', 'subject', 'message')
admin.site.register(Contact, ContactAdmin)

stream - Follow activity is shown in news feed

I have created the following feeds:
notification, timeline_aggregated, user, and timeline.
In my application, users can create posts and follow other users. Users view the posts from people that they follow. However, when I retrieve an individual user's news feed, follow actions are included along with post actions. I've spent a lot of time attempting to figure out why this is. Possibly I am missing something?
Thanks.
class AppBaseModel(models.Model):
created_at = models.DateTimeField(blank=True, null=True, auto_now_add=True)
deleted_at = models.DateTimeField(blank=True, null=True)
class Meta:
abstract = True
class UserFollow(AppBaseModel, Activity):
class Meta:
verbose_name = 'UserFollow'
verbose_name_plural = 'UserFollows'
user = models.ForeignKey(API_USER_MODEL, on_delete=models.CASCADE, related_name='following_set')
target_user = models.ForeignKey(API_USER_MODEL, on_delete=models.CASCADE, related_name='follower_set')
#property
def activity_actor_attr(self):
return self.user
#property
def activity_notify(self):
return [feed_manager.get_notification_feed(self.target_user.id)]
#property
def extra_activity_data(self):
return {'user': self.user.id,
'target_user': self.target_user,
'created_at': self.created_at}
#classmethod
def activity_related_models(cls):
return ['user', 'target_user']
You're inheriting the Activity model when you create your UserFollow class, it will create 'follow' activities and push them into the stream as well.
https://github.com/GetStream/stream-django#model-integration
"Simply mix in the Activity class on the models you want to publish."

Resources