I have two models.
The first one represents different Projects with a name, an ID and a description
The second one is for tracking which user is in which Project.
So my models look like this:
from django.contrib.auth.models import User
# Create your models here.
class Project(models.Model):
id = models.AutoField(db_column = 'db_ID', primary_key = True)
name = models.CharField(max_length=500, default = None)
descriptor = models.CharField(max_length = 1000, null = True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'projects'
def __str__(self):
return self.name
class Userproject(models.Model):
id = models.AutoField(db_column = 'db_ID', primary_key = True)
user = models.ForeignKey(User, on_delete= models.SET_NULL, null = True)
project = models.ForeignKey('Project', on_delete = models.SET_NULL, null = True)
created_at = models.DateTimeField(auto_now_add=True, null=True)
updated_at = models.DateTimeField(auto_now=True, null = True)
class Meta:
db_table = 'UserProjects'
def __str__(self):
return self.id
In the Userproject there there is only the UserID and the ProjectID, both are ForeignKeys to the other models.
When I get a GET-Request with a username, I can get the userID , then I can filter all the Userprojects by the userID and serialize all those where the given user is present. But How would I include the Project data as well If I want to send the name of the Project as well?
So you can run a query with power operators to filter data based on foreign object values.
user_projects = Userproject.objects.filter(user_id=user_id, project__name='yourproject')
Now to access project data from user_project you can use . operator.
if user_projects.exists():
print(user_projects[0].user_id)
print(user_projects[0].project.name)
print(user_projects[0].project.descriptor)
To get values directly from the ORM, use .values().
user_projects = Userproject.objects.filter(user_id=user_id, project__name='yourproject').values('project__name', 'project__descriptor)
This will fetch only the columns you specify as parameters.
Related
i have some active and non active data's in EVENT models and active data has the VISITORS form to fill ..so far i have tried OnetoOne relationship but it didn't succeed ..i am getting both active and non active field in VISITORs model..thank you for your time.
here is models.py
class Event(models.Model):
event_id = models.AutoField
Event_Name = models.CharField(max_length=50)
description = RichTextField()
date_And_time = models.DateTimeField()
location=models.CharField(max_length=50)
slugs = models.SlugField(max_length= 200,default="")
picture = models.ImageField(upload_to='wildlife/picture', default="")
active = models.BooleanField(default=False)
class Meta:
ordering = ["date_And_time"]
def __str__(self):
return self.Event_Name
class Eventvisitor(models.Model):
event = models.OneToOneField(Event, on_delete=models.CASCADE, related_name="eventvistor",default="")
name = models.CharField(max_length=50)
email = models.CharField(max_length=70, default="")
phone = models.CharField(max_length=20,default="")
date = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-date']
def __str__(self):
return self.email
You can limit the choices with limit_choices_to=… [Django-doc]. But likely what you want is a ForeignKey, since otherwise, each Event can have at most one related EventVisitor (a OneToOneField is basically a ForeignKey with a unique=True constraint).
class Eventvisitor(models.Model):
event = models.ForeignKey(
Event,
limit_choices_to={'active': True},
on_delete=models.CASCADE,
related_name='eventvistors'
)
name = models.CharField(max_length=50)
email = models.CharField(max_length=70, default="")
phone = models.CharField(max_length=20,default="")
date = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-date']
def __str__(self):
return self.email
Note that while one can only select Events with active=True, if you later set the .active field to False, items will still link to it, since the relation is not enforced at database level.
I'm trying to filter a table based on a value in another table, via a foreign key.
trench_id = models.ForeignKey(Trench, db_column='trench_id', on_delete = models.PROTECT)
As above, the Context model joins to the Trench model via trench_id__trench_id I want to access trench.name as you can see below I'm then using this value in a filter. I include the views.py code and for reference my models.py.
def allcontexts(request):
allcontexts = Context.objects.filter(trench_id__trench_id__name=request.session.get("name"))
return render(request, 'context_manager/context_manager.html',
{
'allcontexts':allcontexts,
})
I'm getting the following error Unsupported lookup 'name' for AutoField or join on the field not permitted.
models.py
class Trench(models.Model):
trench_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50)
area_easting = models.IntegerField()
area_northing = models.IntegerField()
def __str__(self):
return str(self.name)
class Context(models.Model):
context_id = models.AutoField(primary_key=True)
trench_id = models.ForeignKey(Trench, db_column='trench_id', on_delete = models.PROTECT)
number = models.IntegerField()
type = models.CharField(max_length = 50, blank=True, null=True)
description = models.TextField(blank=True, null=True)
excavation_method = models.CharField(max_length = 50, blank=True, null=True)
open_date = models.DateField(blank=True, null=True)
close_date = models.DateField(blank=True, null=True)
excavated_by = models.CharField(max_length = 50, blank=True, null=True)
area_easting = models.IntegerField()
def __str__(self):
return str(self.number)
Extra troubleshooting
Here's the sql that is being generated, it's not looking in the trench table.
queryset = Context.objects.filter(trench_id__trench_id=4)
print(queryset.query)
SELECT "kap"."context"."context_id", "kap"."context"."trench_id", "kap"."context"."number", "kap"."context"."type", "kap"."context"."description", "kap"."context"."excavation_method", "kap"."context"."open_date", "kap"."context"."close_date", "kap"."context"."excavated_by", "kap"."context"."area_easting"
FROM "kap"."context"
WHERE "kap"."context"."trench_id" = 4 ORDER BY "kap"."context"."number" ASC
Looks to me like it should just be Context.objects.filter(trench_id__name=request.session.get("name")). As written, you're asking for the name attribute of the trench_id AutoField on the Trench model - which of course doesn't exist.
I'm trying to import three datasets for three data models that are interconnected and I cannot seem to properly add in the foreign key. When I try to use the fields.Feild() function to create the foreign key, I get the nameerror in this line: hid = fields.Field(column_name='hid',attribute='hid',..). Please help, I've been trying to upload my datasets for a week. I originally tried to do it manually, but was unable, so now I'm using this package django-import-export.
NameError: name 'fields' is not defined
Here is my models.py
class Service(models.Model):
"""Model representing an author."""
serviceid = models.UUIDField(default=uuid.uuid4, help_text='Unique ID for this particular service in database')
desc_us = models.TextField(blank=True, primary_key = True)
cpt = models.IntegerField(default= 10000)
price = models.DecimalField(max_digits=6, decimal_places=2, blank=True, null=True)
_str__(self):
"""String for representing the Model object."""
return self.desc_us
# Create your models here.
class Library(models.Model):
"""Model representing Librarys."""
hid = models.CharField(max_length = 8, null=True)
name = models.CharField(max_length=200, primary_key=True)
hopid = models.UUIDField(default=uuid.uuid4, help_text='Unique ID for this particular library in database')
address = models.CharField(max_length = 200, null = True)
city = models.CharField(max_length = 50, null = True)
state = models.CharField(max_length = 2, null=True)
zipcode = models.CharField(max_length = 5, null=True)
phone = models.CharField(max_length = 12, null=True)
updateDate = models.DateField(blank=True, null=True)
class Meta:
ordering = ['hopid']
def __str__(self):
"""String for representing the Model object."""
return f'{self.name} ({self.address})'
class Price(models.Model):
"""Model with all the hospital prices by service."""
priceid = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Unique ID for this particular service in database')
com_desc = models.CharField(max_length = 200, blank = True, null = True)
service = models.ForeignKey("Service", on_delete=models.SET_NULL, null=True)
price_offer = models.DecimalField(max_digits=8, decimal_places=2, blank=True)
comments = models.CharField(max_length = 200, blank = True, null =True)
hospital = models.ForeignKey("Hospital", on_delete=models.SET_NULL, null=True)
class Meta:
ordering =['service']
def __str__(self):
return f'{self.hospital.name} ({self.service.desc_us}) ({self.price_offer})'
Here is admin.py
from import_export.admin import ImportExportModelAdmin
from import_export import resources
class ServiceResource(resources.ModelResource):
class Meta:
model = Service
report_skipped = True
exclude = ('id','serviceid')
import_id_fields = ('desc_us', 'cpt', 'price',)
#admin.register(Service)
class ServiceAdmin(ImportExportModelAdmin):
resource_class = ServiceResource
class LibraryResource(resources.ModelResource):
class Meta:
model = Library
report_skipped = True
exclude = ('id','hopid','updateDate')
import_id_fields = ('hid', 'name', 'address', 'city', 'state', 'zipcode', 'phone',)
#admin.register(Library)
class LibraryAdmin(ImportExportModelAdmin):
resource_class = LibraryResource
class PriceResource(resources.ModelResource):
hid = fields.Field(column_name='hid',attribute='hid', widget=ForeignKeyWidget(Library, 'name'))
class Meta:
model = Price
report_skipped = True
exclude = ('id','priceid')
#admin.register(Price)
class PriceAdmin(ImportExportModelAdmin):
list_display = ('com_desc', 'cpt', 'price_offer', 'comments', 'hid',)
resource_class = PriceResource
At the top, add:
import import_export
Then change your line of code to:
hid = import_export.fields.Field(column_name='hid',attribute='hid', widget=ForeignKeyWidget(Library, 'name'))
You're currently not telling Django what library to look for 'fields' in, so it doesn't know.
I created a form with the model form manager. Before saving my TransactionProfile ModelForm, I want to connect it with an order model. When I print session_order_id it is the correct id, however self.order_set.get is always empty when I print it in the console. Anyone can help me with that? Would you in general solve it the way I did it here, or ist there a more clean method?
In my views.py I have the following:
t = transaction_profile.save(commit=False)
t.update_order_with_transaction_profile(session_order_id)
t.save()
transactions/models.py
class TransactionProfile(models.Model):
email = models.EmailField()
address_line_1 = models.CharField(max_length=120)
address_line_2 = models.CharField(max_length=120, null=True, blank=True)
city = models.CharField(max_length=120)
country = models.CharField(max_length=120)
state = models.CharField(max_length=120)
postal_code = models.CharField(max_length=120)
update = models.DateTimeField(auto_now=True)
timestamp = models.DateTimeField(auto_now_add=True)
customer_id = models.CharField(max_length=120, null=True, blank=True)
def update_order_with_transaction_profile(self, session_order_id):
# In ModelManager or just in class TransactionProfile
o = self.order_set.get(order_id=session_order_id)
o.transaction_profile = self
o.save()
orders/models.py
class Order(models.Model):
order_id = models.CharField(max_length=10, unique=True)
customer_key = models.CharField(max_length=10, unique=True)
updated = models.DateTimeField(auto_now=True)
timestamp = models.DateTimeField(auto_now_add=True)
transaction_profile = models.ForeignKey(TransactionProfile, blank=True, null=True, on_delete=models.CASCADE)
You need to save object to DB before using it as foreign key. Since in your code t is not saved in DB, update_order_with_transaction_profile will not work.
Instead of self.order_set, which gives you only orders related to specific profile(empty list for new object), you can directly query on Order model, note you need to save transaction_profile firts:
t = transaction_profile.save()
t.update_order_with_transaction_profile(session_order_id)
def update_order_with_transaction_profile(self, session_order_id):
# In ModelManager or just in class TransactionProfile
o = Order.objects.get(order_id=session_order_id)
o.transaction_profile = self
o.save()
I have seen a lot of posts on how to deserialize and serialize nested relationships of tables having a many to many relationship, but when an intermediate table is used in a many to many relationship I am not able to achieve deserialization.
This is because an intermediate table requires two foreign keys, one each from the two tables participating in the relation.
I have an Order model and a Service model which are in a many to many relationship via an OrderItem intermediate table.
I need to pass a JSON request like this:
{"service_time":"2015-11-14 10:00:51+0530",
"address":"xyz",
"items":[{"order": "1", "service_id":"4"},
{"order":"1", "service_id":"5"}]
}
The "service_time" and "address" elements get saved in the Order table. Now the problem arises with the "items" JSON array. I pass the "service_id" (foreign key to the Service table) and I need to pass "order" (foreign key to the Order table) too as it is a required field. The problem is that the primary key of the Order table is not known when the request is sent(as the Order is also created as a part of the same request). How can I achieve deserialization in this scenario?
I tried something like this but it didn't work out.
class OrderSerializer(serializers.ModelSerializer):
items = ItemSerializer(many=True)
class Meta:
model = Order
def create(self, validated_data):
items_data = validated_data.pop('items')
orders = Order.objects.create(**validated_data)
for item in items_data:
#order = item['order']
service = item['service']
//Passing the Order object just created as the foreign key of OrderItem
orderItem = OrderItem.objects.create(order=orders, service=service)
orderItem.save()
return orders
class ServiceSerializer(serializers.ModelSerializer):
group = serializers.CharField(source="group.group_name")
category = serializers.IntegerField(source="group.category_id")
class Meta:
model = Service
fields = ['id', 'service_name', 'price', 'special_price', 'service_time', 'group', 'category']
class ItemSerializer(serializers.ModelSerializer):
service_detail = ServiceSerializer(source="service", read_only=True)
class Meta:
model = OrderItem
I get an error saying 'Service' object has no attribute 'order'.
I know the Service model does not have an "order" attribute, but I am creating an OrderItem object, not a Service object.
Any suggestions will be helpful!
Edit: Adding the models used
class Order(models.Model):
STATUSES = [('PENDING', 'Pending'), ('PROCESSING', 'Processing'), ('COMPLETE', 'Complete'), ('CANCELED', 'Canceled')]
PAYMENT_STATUSES = [('PENDING', 'Pending'), ('PAID', 'Paid'),]
CANCEL_REASON = [('NO_SERVICE', 'No Service In Area'), ('NO_STYLIST', 'Stylist Not Available'), ('STYLIST_REFUSED', 'Stylist Refused After Accepting',),
('CUSTOMER_UNREACHABLE', 'Customer Not Reachable'), ('CUSTOMER_CANCELED', 'Customer Canceled at Fisrt Call'), ('CUSTOMER_REFUSED', 'Customer Refused at Last Moment'),
('DUPLICATE_ORDER', 'Duplicate Order'), ('MALE_CLIENT', 'Male Client'), ('CALLCENTER_DELAY', 'Delay/Error at Frontdesk')]
serial = models.CharField(max_length=10, null=True, blank=True,)
customer = models.ForeignKey(Customer, verbose_name="customer", related_name="ordersbycustomer")
stylist = models.ForeignKey(Stylist, null=True, blank=True, verbose_name="stylist", related_name="ordersbystylist")
# TODO, Use timezone.now
service_time = models.DateTimeField(default=timezone.now, blank=True)
started_moving = models.DateTimeField(null=True, blank=True)
service_start_at = models.DateTimeField(null=True, blank=True)
service_end_at = models.DateTimeField(null=True, blank=True)
reached_safely = models.DateTimeField(null=True, blank=True)
sub_total = models.FloatField(default=0)
discounts = models.FloatField(default=0)
grand_total = models.FloatField(default=0)
total_time = models.IntegerField(default=0)
status = models.CharField(max_length=32, choices=STATUSES, default='PENDING')
payment_status = models.CharField(max_length=32, choices=PAYMENT_STATUSES, default='PENDING')
items = models.ManyToManyField(Service, through='OrderItem')
address = models.ForeignKey(Address, null=True, blank=True, related_name='+', on_delete=models.SET_NULL)
amount_received = models.FloatField(default=0)
send_sms = models.BooleanField(default=True)
thru_app = models.BooleanField(default=True)
referral_discount = models.FloatField(default=0)
cancellation_reason = models.CharField(max_length=64, choices=CANCEL_REASON, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.serial
def _get_service_list(self):
return ','.join(str(p.description) for p in self.items.all())
service_list = property(_get_service_list)
class Service(models.Model):
group = models.ForeignKey(Group, related_name="services")
service_name = models.CharField(max_length=128)
price = models.FloatField(default=0)
special_price = models.FloatField(default=0)
service_time = models.IntegerField()
description = models.CharField(max_length=123)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __unicode__(self):
return '{} ({})'.format(self.service_name, self.group)
class OrderItem(models.Model):
order = models.ForeignKey(Order)
service = models.ForeignKey(Service)
price = models.FloatField(default=0)
special_price = models.FloatField(default=0)
qty = models.IntegerField(default=1)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.service.service_name
Edit2: Added the other related serializers.
One important thing I forgot to mention is that, the data gets saved in the DB, but the exception is still raised.