Django is rendering an awkward result - python

Basically, I am working on a django project, and whenever I insert data into the database, the result is weirdly formatted.
this is my model
customer.py
class Customer(models.Model):
user = models.OneToOneField(User,null=True,blank=True,on_delete=models.CASCADE)
name = models.CharField(max_length=200, null=True)
email= models.CharField(max_length=200, null=True)
phone_number= models.CharField(max_length=200, null=True)
def __str__(self):
return self.name
Now, say I have saved a new customer
new_customer = Customer.objects.create(name="Henry",email="henry#mail.com",phone_number="+330145786259")
new_customer.save()
when i try to retrieve the customer name i get this:
print(new_customer.name)
>('henry',)
Anyone has any insight for me???
I tried to recreate the model on a new project but still having the same result

In your customer class, you have defined a 1:1 relationship with the in-built user model class of django. And when you are creating the customer object, new_customer, you have not specified the 'user' attribute; hence, your customer object is missing a key element.
The user object already has an in-built field for storing names. It is 'first_name' and 'last_name.' You need to create a user model first before being able to create your 'Customer' model.
Your models.py should look something like this:
from django.contrib.auth.models import User
class Customer(models.Model):
user = models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE)
phone_number= models.CharField(max_length=200, null=True)
def __str__(self):
return self.user.first_name
# to return email -> self.user.email
Now to create a 'Customer' object in view.py:
from django.contrib.auth.models import User
from .models import Customer
# create a user object
myuser = User.objects.create_user(username='john', email='jlennon#beatles.com', password='glass onion')
# pass the user object to the customer model
mycustomer = Customer.objects.create(user=myuser, phone_number=123456789)
# save the customer object
mycustomer.save()
Explore django ModelForms to define the user model as per your specifications, e.g, if you don't require your users to have passwords associated with them, etc.

After much testing, I realized why I was getting the weird output.
I was directly passing data from a form to the object creation method, like so:
data = json.loads(request.body)
new_customer = Customer.objects.create(name=data['name'],email="henry#mail.com",phone_number="+330145786259")
new_customer.save()
So assigning the received data to a variable before passing it to the object creation method seems to be the right way of doing things... At least, it is working for me.

Related

Django rest framework create password for custom user model

Actually I'm creating an employee management system project using django rest api.
Now i have created my own custom models like shown below, i want to create the register employee with the below models. But how can i set the password field for login, since I haven't included in my fields. I've attached my models and serializer. Please do help for me. I'm beginner
Class Employee (models.Model):
name = models.CharField(max_length=50, unique=True, verbose_name='None')
email = models.EmailField(verbose_name='Email')
department = models.CharField(max_length=30, unique=False, verbose_name='Departamento')
(And many more details like personal email,contact, and many)
# Function used to display the employee's name in the admin page
def __str__(self):
return self.name
My serializer class is
class Employee DetailsSerializer(serializers.ModelSerializer):
class Meta:
model = Employee
Fields = [__all__]
My views be like, i want to create register view, since i dont have password in my model, how to create password field to my above shown register field,
Whatever maybe my register field should contain all those above details. I'm scratching my head here.please someone help
Yes, you can add a password field in your Employee model but you are requested not to do it because Django already provided this type of facility. Just you have to know How to use it. Try to extend the existing User model from django.contrib.auth.models.User.Let's organize your Employee model.
from django.contrib.auth.models import User
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
#name = models.CharField(max_length=50, unique=True,
verbose_name='None')
#email = models.EmailField(verbose_name='Email')
department = models.CharField(max_length=30, unique=False,
verbose_name='Departamento')
#property
def name(self):
return "{0} {1}".format(self.user.first_name,
self.user.last_name)
No need to add an email field because this field already exists in the User model and the name field can be a property that retrieves data from the user model and the rest of the code will be unchanged. So you are concerned about the password field and it also exists in the User model.
Please check out this repo and it might help you.

DJANGO get objects in sql like join

Context: I'm forcing my self to learn django, I already wrote a small php based website, so I'm basically porting over the pages and functions to learn how django works.
I have 2 models
from django.db import models
class Site(models.Model):
name = models.CharField(max_length=50, unique=True)
def __str__(self):
return self.name
class Combo(models.Model):
username = models.CharField(max_length=50)
password = models.CharField(max_length=50)
dead = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True)
siteID = models.ForeignKey(Site, on_delete=models.PROTECT)
class Meta:
unique_together = ('username','siteID')
def __str__(self):
return f"{self.username}:{self.password}#{self.siteID.name}"
When creating a view, I want to get the Combo objects, but I want to sort them first by site name, then username.
I tried to create the view, but get errors about what fields I can order by Cannot resolve keyword 'Site' into field. Choices are: dead, id, password, siteID, siteID_id, timestamp, username
def current(request):
current = Combo.objects.filter(dead=False).order_by('Site__name','username')
return render(request, 'passwords/current.html',{'current':current})
Since I'm not necissarily entering the sites into the database in alphabetical order, ordering by siteID wouldn't be useful. Looking for some help to figure out how to return back the list of Combo objects ordered by the Site name object then the username.
You can order this by siteID__name:
def current(request):
current = Combo.objects.filter(dead=False).order_by('siteID__name','username')
return render(request, 'passwords/current.html',{'current':current})
since that is the name of the ForeignKey. But that being said, normally ForeignKeys are not given names that end with an ID, since Django already adds an _id suffix at the end for the database field.
Normally one uses:
class Combo(models.Model):
# …
site = models.ForeignKey(Site, on_delete=models.PROTECT)
if you want to give the database column a different name, you can specify that with the db_column=… parameter [Django-doc]:
class Combo(models.Model):
# …
site = models.ForeignKey(
Site,
on_delete=models.PROTECT,
db_column='siteID'
)

Using the Django admin site for specific instances of a model

I am working on my first Django app, and was thinking of using a rather abstract database schema, like this:
class ListCategories(models.Model):
name = models.TextField(max_length=200)
type = models.TextField(max_length=200)
class ListItems(models.Model):
category = models.ForeignKey('ListCategories', on_delete=models.CASCADE)
item = models.TextField(max_length=200)
sorstorder = models.IntegerField()
class ObjectType(models.Model):
name = models.TextField(max_length=200)
class Object(models.Model):
type = models.ForeignKey('ObjectType', on_delete=models.CASCADE)
name = models.TextField(max_length=200)
class ObjectTypeProperties(models.Model):
name = models.TextField(max_length=200)
object_type = models.ForeignKey('ObjectType', on_delete=models.CASCADE)
list_category = models.ForeignKey('ListCategories', null=True, on_delete=models.CASCADE)
class ObjectProperties(models.Model):
object = models.ForeignKey('Object', on_delete=models.CASCADE)
property = models.ForeignKey('ObjectTypeProperties', on_delete=models.CASCADE)
list_item = models.ForeignKey('ListItems', on_delete=models.CASCADE)
result = models.TextField(max_length=200)
class HistoricalNumericalData(models.Model):
object = models.ForeignKey('Object', on_delete=models.CASCADE)
object_property = models.ForeignKey('ObjectProperties', on_delete=models.CASCADE)
value = models.FloatField()
class Image(models.Model):
object = models.OneToOneField('Object',on_delete=models.CASCADE)
image = models.ImageField()
def image_tag(self):
return mark_safe('<img src="{}"/>'.format(self.image.url))
image_tag.short_description = 'Image'
This is very flexible on the DB, as you can add object types and object properties by simply adding lines to the DB. However, I would like to use the admin interface to add new Objects to the database, and this is where this schema is tricky to use. The form would need to be different for each object type, however, as they would have not the same properties.
Is there a way to register models to use with the admin site that behave differently according to a field in a model? In my case, the Object.type field would dictate the nature of the form.
Would it be better to just define more concrete models?
You can try to use ModelAdmin.get_fieldsets() method, as you receive an object instance you can modify which fieldsets you want to publish, check the docs -> https://docs.djangoproject.com/en/2.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_fieldsets
Otherwise, U can explore to use ModelAdmin.get_form(), build custom forms for each Object.type and instantiate de proper one for each case, docs here -> https://docs.djangoproject.com/en/2.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_form
Hope this puts you on the right way.
G.

How to insert data into a relational one to one table in django?

I have a UserProfile table which is in relation with the default Django User table. Here's how it looks.
class UserProfile(models.Model):
user = user.OneToOneField(User, on_delete=models.CASCADE)
section = models.CharField(max_length=255, blank=True)
year = models.IntegerField(null=True, blank=True)
course = models.CharField(max_length=255, blank=True)
qrcode = models.CharField(max_length=255, blank=True)
present = models.BooleanField(default=False)
I am trying to insert the data into the UserProfile table using the Django Shell.
from users.models import UserProfile
a = UserProfile(qrcode="hello")
a.save()
This is how I have always known to insert data into tables, it has always worked. BUT when i try to do this in UserProfile model. I get this exception. NOT NULL constraint failed: users_userprofile.user_id. Which in turn is caused by the following exception Error in formatting: RelatedObjectDoesNotExist: UserProfile has no user.
I somewhat understand that I somehow need to supply a user instance. But I am clueless as to how. Can someone please help me.
Firstly you need to create User.
u1 = User(username='user1')
u1.save()
Create a UserProfile. Pass the ID of the “parent” object as this object’s ID:
v1 = UserProfile(user=u1, ....)
v1.save()
refer this
You need to create your User first
user = User.objects.create(username='user')
and then you can do:
user_profile = UserProfile.objects.create(user=user, ...)

Django Rest update many to many by id

I'm novice in python and django rest. But I'm confused. What is the best way to update many to many relation in django rest framework.
I read the docs
http://www.django-rest-framework.org/api-guide/relations/#manytomanyfields-with-a-through-model
By default, relational fields that target a ManyToManyField with a through model specified are set to read-only.
If you explicitly specify a relational field pointing to a ManyToManyField with a through model, be sure to set read_only to True.
So if I have a code
class Master(models.Model):
# other fields
skills = models.ManyToManyField(Skill)
class MasterSerializer(serializers.ModelSerializer):
skills = SkillSerializer(many=True, read_only=False)
This will return skills as list of objects. And I don't have a way to update them. As far as I understood Django prefers work with objects vs object id when it comes to M2M. If I work with yii or rails I will work with "through" models. I would like to get skill_ids field. That I could read and write. And I can do this for write operation
class MasterSerializer(serializers.ModelSerializer):
skill_ids = serializers.ListField(write_only=True)
def update(self, instance, validated_data):
# ...
validated_data['skill_ids'] = filter(None, validated_data['skill_ids'])
for skill_id in validated_data['skill_ids']:
skill = Skill.objects.get(pk=skill_id)
instance.skills.add(skill)
return instance
But I cannot make it return skill_ids in field. And work for read and write operations.
A few things to note.
First, you don't have an explicit through table in your example. Therefore you can skip that part.
Second, you are trying to use nested serializers which are far more complex than what you're trying to achieve.
You can simply read/write related id by using a PrimaryKeyRelatedField:
class MasterSerializer(serializers.ModelSerializer):
skills_ids = serializers.PrimaryKeyRelatedField(many=True, read_only=False, queryset=Skill.objects.all(), source='skills')
Which should be able to read/write:
{id: 123, first_name: "John", "skill_ids": [1, 2, 3]}
Note that the mapping from JSON's "skill_ids" to model's "skills" is done by using the optional argument source
I will try to bring some light in terms of design: in Django if you specify the model for a ManyToManyRelation, then the relation field on the model becomes read-only. If you need to alter the associations you do it directly on the through model, by deleting or registering new records.
This means that you may need to use a completely different serializer for the through model, or to write custom update/create methods.
There are some sets back with custom through model, are you sure you're not good enough with the default implementation of ManyToManyFields ?
tl;dr:
For a much simpler, one-liner solution for M2M, I sussed out a solution of the form:
serializer = ServiceSerializer(instance=inst, data={'name':'updated', 'countries': [1,3]}, partial=True)
if serializer.is_valid():
serializer.save()
For a more complete example, I have included the following:
models.py
from django.db import models
class Country(models.Model):
name = models.CharField(max_length=50, null=False, blank=False)
class Service(models.Model):
name = models.CharField(max_length=20, null=True)
countries = models.ManyToManyField('Country')
serializers.py
from rest_framework import serializers
from .models import *
class CountrySerializer(serializers.ModelSerializer):
class Meta:
model = Country
fields = ('name',)
class ServiceSerializer(serializers.ModelSerializer):
class Meta:
model = Service
fields = ('name', 'countries',)
Make sure some dummy service and country instances are created for testing. Then you can update an instance in a function like so:
Update example
# get an object instance by key:
inst = ServiceOffering.objects.get(pk=1)
# Pass the object instance to the serializer and a dictionary
# Stating the fields and values to update. The key here is
# Passing an instance object and the 'partial' argument:
serializer = ServiceSerializer(instance=inst, data={'name':'updated', 'countries': [1,3]}, partial=True)
# validate the serializer and save
if serializer.is_valid():
serializer.save()
return 'Saved successfully!'
else:
print("serializer not valid")
print(serializer.errors)
print(serializer.data)
return "Save failed"
If you inspect the relevant tables, the updates are carried through including to the M2M bridging table.
To extend this example, we could create an object instance in a very similar way:
### Create a new instance example:
# get the potential drop down options:
countries = ['Germany', 'France']
# get the primary keys of the objects:
countries = list(Country.objects.filter(name__in=countries).values_list('pk', flat=True))
# put in to a dictionary and serialize:
data = {'countries': countries, 'name': 'hello-world'}
serializer = ServiceOfferingSerializer(data=data)
I have dealt with this issue for quite some time and I have found that the best way to solve the general problem of updating any many to many field is by working around it.
In my case there is a model called Listing and a user can make a Subscription(the other model) to an instance of the Listing model. The Subscription works with a Generic Foreign Key and the Listing imports the Subscriptions of the users via Many2Many.
Instead of making a PUT request to the Listing Model via API, I simply add the Subscription instance to the right model in the POST Method of the API View of Subscription. Here is my adjusted code:
#Model
class Listing(models.Model):
#Basics
user = models.ForeignKey(settings.AUTH_USER_MODEL)
slug = models.SlugField(unique=True, blank=True)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
#Listing
title = models.CharField(max_length=200)
price = models.CharField(max_length=50, null=True, blank=True)
subscriptions = models.ManyToManyField(Subscription, blank=True)
class Subscription(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
timestamp = models.DateTimeField(auto_now_add=True)
#Views
class APISubscriptionCreateView(APIView): #Retrieve Detail
def post(self, request, format=None):
serializer = SubscriptionCreateSerializer(data=request.data)
if serializer.is_valid():
sub = serializer.save(user=self.request.user)
object_id = request.data['object_id']
lis = Listing.objects.get(pk=object_id)
lis.subscriptions.add(sub)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I hope this will help, it took me a while to figure this out

Categories