Django Foreign Key Aliasing - django

I'm trying to be able to alias a column name from a model's foreign key. I want to be able to change 'owner__username' to just 'username' when passing a JSON response.
query_n = Example.objects.values('owner__username','name')
print(query_n[0])
Which prints
{'name': 'e_adam', 'owner__username': 'adam'}
The only renaming of a column I have seen was via annotate() however, that isn't even truly a column (AVG, SUM, ...)
The Example model has a foreign key owner, which is 'auth.User' model.
Any thoughts?

I'm not too sure about this but if you are using django >= 1.7, sounds like you could use annotate to create alias for named arguments in values(). I found a related django ticket, to quote from the latest response:
Just quickly, with the changes to annotate that have landed, it is now
possible to create aliases yourself, and reference them from the
values call:
from django.db.models import F
Model.objects.annotate(my_alias=F('some__long__name__to__alias')) \
.values('my_alias')

aliasName = models.ForeignKey(modelName, to_field='fieldName', on_delete=models.CASCADE)
This is the format for aliasing in Django Foreign Key
Here is full Models page
from django.db import models
# Create your models here.
class Farm(models.Model):
srFarm = models.AutoField(primary_key=True)
name = models.CharField(max_length = 264, unique =True)
address = models.CharField(max_length = 264)
def __str__(self):
temp = '{0.name},{0.address}'
return temp.format(self)
class Batch(models.Model):
srBatch = models.AutoField(primary_key=True)
farmName = models.ForeignKey(Farm, to_field='name', on_delete=models.CASCADE)
def __str__(self):
temp = '{0.farmName}'
return temp.format(self)

Related

How to bypass WSGI error in django filter

from django.db import models
from django.contrib.auth.models import User
class Transfer(models.Model):
id = models.AutoField(primary_key=True)
amount = models.DecimalField(max_digits=10, decimal_places=2)
name=models.CharField(max_length=55)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
Is it possible to make a request like this without WSGI error?
result = Transfer.objects.filter(name=request.name)
filter()
filter(**kwargs)
Returns a new QuerySet containing objects that match the given lookup parameters.
The lookup parameters (**kwargs) should be in the format described in Field lookups below.
Where charfield == String object, so try to str(request.name)

I want add two annotation for two foreign keys using Django. How do I do this?

# models.py
from django.db import models
class Elephant(models.Model):
location = models.ForeignKey(Location, on_delete=models.CASCADE)
families = models.ForeignKey(Families, on_delete=models.CASCADE)
def add_families_and_locations_counts(elephants):
return elephants.annotate(
families_number=Count('families'),
location_number=Count('location')
)
# Run
output = add_families_and_locations_counts(elephants)
In the above, the counts are incorrect. How do I get the correct counts?
You want to count the distinct foreign key model instances.
Update your annotations function to the below:
def add_families_and_locations_counts(elephants):
return elephants.annotate(
families_number=Count('families', distinct=True),
location_number=Count('location', distinct=True)
)

Django: unable to create Generic Foreign key object

I'm using Django 2.x
I have two models
class DynamicUrlObject(models.Model):
content_type = models.ForeignKey(ContentType, null=True, on_delete=models.SET_NULL)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
domain = models.CharField(max_length=255)
and
class MyModel(models.Model):
name = models.Char(max_length=50)
my_obj = fields.GenericRelation(DynamicUrlObject, related_query_name='my_obj')
I have an object of MyModel and want to create a record for DynamicUrlObject and link same to the MyModel model.
I'm doing it something like
dy_obj = DynamicUrlObject.objects.get_or_create(
content_object=my_existing_obj,
domain='http://example.com'
)
my_existing_obj.my_obj = dy_obj
my_existing_obj.save()
But this is not creating a record for DynamicUrlObject and gives an error as
django.core.exceptions.FieldError: Field 'content_object' does not generate an
automatic reverse relation and therefore cannot be used for reverse querying.
If it is a GenericForeignKey, consider adding a GenericRelation.
You cannot filter or get directly on a generic foreign key [1], so get_or_create() won't work. If you know the type of my_existing_obj is MyModel, you can use the GenericRelation you set on MyModel:
try:
dy_obj = DynamicUrlObject.objects.get(my_obj=my_existing_object, domain=...) # use the `related_query_name` here
except DynamicUrlObject.DoesNotExist:
dy_obj = DynamicUrlObject(content_object=my_existing_object, domain=...)
dy_obj.save()
Also once you've created dy_obj, you don't need to assign the reverse relationship to my_existing_object. The GenericRelation isn't a concrete field in the db, it's just a way for django ORM to know how to name the relationships.
[1] https://docs.djangoproject.com/en/2.2/ref/contrib/contenttypes/#django.contrib.contenttypes.fields.GenericForeignKey

Making use of the users table, causing an error

In Django (2.x) I have an entry form, the model is here:
from django.db import models
from django.contrib.auth.models import User
from django.conf import settings
class Sample(models.Model):
sample_id = models.AutoField(primary_key=True)
area_easting = models.IntegerField()
area_northing = models.IntegerField()
context_number = models.IntegerField()
sample_number = models.IntegerField()
# taken_by = models.IntegerField()
taken_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete = models.PROTECT)
def __str__(self):
return str(self.sample_id)
class Meta:
db_table = 'samples\".\"sample'
#ordering = ["sample_id"]
managed = False
#verbose_name_plural = "samples"
This works as expected, a list of usernames drops down (while I would like to format - firstname lastname). However, when I return to the main viewing page I see an error.
django.db.utils.ProgrammingError: column sample.taken_by_id does not exist
LINE 1: ...text_number", "samples"."sample"."sample_number", "samples"....
^
HINT: Perhaps you meant to reference the column "sample.taken_by".
Clearly Django is adding the _id to the table name causing the error, I expect because it is a foreign key.
Any ideas how to remedy this behaviour?
You can explicitly set the underlying db column via the db_column attribute:
taken_by = models.ForeignKey(settings.AUTH_USER_MODEL, db_column='taken_by', on_delete=models.PROTECT)
https://docs.djangoproject.com/en/2.1/ref/models/fields/#database-representation
^ link to the docs where it specifies that it creates a _id field.
based from the error message you have posted. It seems that your database schema is not updated.
you might need to do manage makemigrations and migrate to apply your model changes to your db schema
e.g
$ python manage.py makemigrations
# to apply the new migrations file
$ python manage.py migrate

django: how do I query based on GenericForeignKey's fields?

I'm new in using GenericForeignKey, and I couldn't make it to work in a query statement. The tables are roughly like the following:
class Ticket(models.Model):
issue_ct = models.ForeignKey(ContentType, related_name='issue_content_type')
issue_id = models.PositiveIntegerField(null=True, blank=True)
issue = generic.GenericForeignKey('issue_ct', 'issue_id')
class Issue(models.Model):
scan = models.ForeignKey(Scan)
A scan creates one issue, an issue generates some tickets, and I made Issue as a foreign key to Ticket table. Now I have a Scan object, and I want to query for all the tickets that related to this scan. I tried this first:
tickets = Tickets.objects.filter(issue__scan=scan_obj)
which doesn't work. Then I tried this:
issue = Issue.objects.get(scan=scan_obj)
content_type = ContentType.objects.get_for_model(Issue)
tickets = Tickets.objects.filter(content_type=content_type, issue=issue)
Still doesn't work. I need to know how to do these kind of queries in django? Thanks.
The Ticket.issue field you've defined will help you go from a Ticket instance to the Issue it's attached to, but it won't let you go backwards. You're close with your second example, but you need to use the issue_id field - you can't query on the GenericForeignKey (it just helps you retrieve the object when you have a Ticket instance). Try this:
from django.contrib.contenttypes.models import ContentType
issue = Issue.objects.get(scan=scan_obj)
tickets = Ticket.objects.filter(
issue_id=issue.id,
issue_ct=ContentType.objects.get_for_model(issue).id
)
Filtering across a GenericForeignKey can by creating a second model that shares the db_table with Ticket. First split up Ticket into an abstract model and concrete model.
class TicketBase(models.Model):
issue_ct = models.ForeignKey(ContentType, related_name='issue_content_type')
issue_id = models.PositiveIntegerField(null=True, blank=True)
class Meta:
abstract = True
class Ticket(TicketBase):
issue = generic.GenericForeignKey('issue_ct', 'issue_id')
Then create a model that also subclasses TicketBase. This subclass will have all the same fields except issue which is instead defined as a ForeignKey. Adding a custom Manager allows it to be filtered to just a single ContentType.
Since this subclass does not need to be synced or migrated it can be created dynamically using type().
def subclass_for_content_type(content_type):
class Meta:
db_table = Ticket._meta.db_table
class Manager(models.Manager):
""" constrain queries to a single content type """
def get_query_set(self):
return super(Manager, self).get_query_set().filter(issue_ct=content_type)
attrs = {
'related_to': models.ForeignKey(content_type.model_class()),
'__module__': 'myapp.models',
'Meta': Meta,
'objects': Manager()
}
return type("Ticket_%s" % content_type.name, (TicketBase,), attrs)