How to amend Models.py to Changes url representation - url

I am implementing a project on django rest framework (filemanager). I need the url field for the "FILE" data type to be in this form as "url": "/file/url1". For the "FOLDER" class, the "url" field should output "url": None. What do I need to write for this in model.py .
Current model.py code looks like:
FILE='FILE'
FOLDER='FILE'
TYPE_CHOICES = [(FILE,"FILE"),(FILE,"FOLDER")]
class Folder(models.Model):
id = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4, null=False)
parentId = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True)
type = models.CharField(max_length=255, choices=TYPE_CHOICES, editable=False, default='FOLDER')
size = models.IntegerField(blank=True, null=True, default = 0)
date = models.DateTimeField(auto_now=True)
url = None
# children = models.ForeignKey('self', models.SET_NULL, null=True)
class File(models.Model):
type = models.CharField(max_length=255, choices=TYPE_CHOICES, editable=False, default='FILE')
id = models.UUIDField(primary_key=True, editable=False, default=uuid.uuid4, null=False)
file = models.FileField(null=True, max_length=255)
date = models.DateTimeField(auto_now =True)
parentId = models.ForeignKey(Folder, on_delete=models.CASCADE, null=True, blank=True, related_name='children')
# url = models.URLField(max_length=200, default=None, null=True, blank=True)
size = models.IntegerField(null=True, blank=True, default=0)
def __str__(self):
return str(self.file.name)

Related

Django Admin list display cannot access foreign key attribute getting 'NoneType' object has no attribute

I'm trying to display a related field in the admin section but I'm getting the following error:
'NoneType' object has no attribute 'ref_code'
models.py
class Orden(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
producto = models.ManyToManyField(
ProductosOrden)
medio_de_venta = models.ForeignKey(MediosVenta, null=True, blank=False, on_delete=models.SET_NULL)
fecha_venta = models.DateField(blank=False, null=False)
ordenado = models.BooleanField(default=False)
ref_code = models.CharField(max_length=20, blank=True, null=True)
promo = models.ForeignKey(Promos,null=True, blank=True, on_delete=CASCADE )
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
vendido_por = models.CharField(max_length=20, null=False, blank=False)
class Meta:
verbose_name_plural = "Ordenes"
ordering = ["-id"]
def __str__(self):
return self.user.username
class Cliente(models.Model):
nombre = models.CharField(max_length=60, null=False, blank=False)
email = models.EmailField(blank=False, null=False)
email_valido = models.BooleanField(null=True, blank= True, verbose_name='Email Válido')
telefono = models.CharField(
max_length=17, null=True, blank=True, verbose_name='Teléfono')
lead = models.ForeignKey(Leads, models.SET_NULL, null=True, blank=True)
activo = models.BooleanField(default=False)
orden = models.ForeignKey(Orden, null=True, blank=True, on_delete=CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
created_by = models.CharField(max_length=20, null=False, blank=False)
class Meta:
verbose_name_plural = "Clientes"
ordering = ["-id"]
def __str__(self):
return self.nombre
admin.py
class ClienteAdmin(admin.ModelAdmin):
list_display = ('id', 'nombre', 'activo', 'get_ref_code')
readonly_fields=('id',)
search_fields = ['nombre']
actions = ['activa','desactivar']
#admin.action(description='Desactivar')
def desactivar(self, request, queryset):
queryset.update(activo = False)
#admin.action(description='Activar')
def desactivar(self, request, queryset):
queryset.update(activo = True)
#admin.display(description= 'ref_code')
def get_ref_code(self, obj):
if not obj.orden.ref_code:
return None
else:
return obj.orden.ref_code
If I just use the return as:
return obj.orden
results are displayed with the name, but I want to display the ref_code results which is under the Orden model and it is not working.
correct if condition because orden column is nullable in Cliente model.
#admin.display(description= 'ref_code')
def get_ref_code(self, obj):
if not obj.orden_id:
return None
else:
return obj.orden.ref_code

Django Admin Change Form : How To avoid using __str__ in header of Django Admin Change Form?

Hi does anyone know if it is possible to avoid Django rendering str for model when in the change admin form? My str method has multiple attributes rendered as shown below:
class Product(models.Model):
"""
Product
"""
id = models.PositiveBigIntegerField(primary_key=True)
attributes = models.JSONField()
labels = models.JSONField()
name = models.TextField()
relative_url = models.TextField(max_length=250)
image = models.URLField()
delivery = models.TextField(max_length=50)
online = models.BooleanField()
is_customizable = models.BooleanField()
is_exclusive = models.BooleanField()
url = models.URLField()
max_price = models.PositiveIntegerField()
min_price = models.PositiveIntegerField()
currency = models.ForeignKey(Currency, on_delete=models.CASCADE)
discount_percentage = models.PositiveSmallIntegerField(default=0)
recommended_retail_price = models.PositiveIntegerField()
def __str__(self) -> str:
product_str = (
f"id: {self.id}\n"
f"attributes: {self.attributes}\n"
f"labels: {self.labels}\n"
f"name: {self.name}\n"
f"relative_url: {self.relative_url}\n"
f"image: {self.image}\n"
f"delivery: {self.delivery}\n"
f"online: {self.online}\n"
f"is_customizable: {self.is_customizable}\n"
f"is_exclusive: {self.is_exclusive}\n"
f"url: {self.url}\n"
f"max_price: {self.max_price}\n"
f"min_price: {self.min_price}\n"
f"currency: {self.currency}\n"
f"discount_percentage: {self.discount_percentage}\n"
f"recommended_retail_price: {self.recommended_retail_price}\n"
)
return product_str

GDALException OGR failure

I am working with Django DRF and GeoDjango for a simple model which is as follows.
class Company(models.Model):
name = models.CharField(max_length=200, default='Company', null=True)
def __unicode__(self):
return self.name
class Shop(models.Model):
name = models.CharField(max_length=200, default="bla")
address = models.CharField(max_length=300, default='blabla')
location = models.PointField(null=True, blank=True, geography=True)
company = models.ForeignKey(
Company, on_delete=models.CASCADE, null=True)
This is its serializer.py
class ShopSerializer(serializers.ModelSerializer):
distance = serializers.DecimalField(
source='distance.km', max_digits=10, decimal_places=2, required=False, read_only=True)
class Meta:
model = Shop
fields = ['id', 'name', 'address', 'location', 'distance']
# read_only_fields = ['distance']
class CompanySerializer(serializers.ModelSerializer):
shop_set = ShopSerializer(many=True)
class Meta:
model = Company
fields = ['id', 'name', 'shop_set']
def create(self, validated_data):
shop_validated_data = validated_data.pop('shop_set')
company = Company.objects.create(**validated_data)
shop_set_serializer = self.fields['shop_set']
for each in shop_validated_data:
each['company'] = company
shops = shop_set_serializer.create(shop_validated_data)
return company
everything works fine until I add rest_framework_gis in my settings.py file or add the following line in my shop serializer
serialize('geojson', Shop.objects.all(),
geometry_field='location', fields=('name', 'address'))
In both the cases get GDALException OGR failure.
I have checked my versions of GDAL and Python. Both are 64 bit. And both python and GDAL are working fine.
What I basically need to do here is to convert my POINT field into json lat long response right now the response is as such (if i do not include the lines that cause error).
{
"id": 1,
"name": "Cosmetica",
"address": "somwhere",
"location": "SRID=4326;POINT (24.896 67.182)"
}
Please help.

Django Admin prepopulate user's email

I need some help to prepopulate user's email in my models. There has to be an easy way, but i think i am too tired to see the trick. Basically what i need, after the user has been logged in to admin, i need those fields like user, email and name from the User model to be already populated with the info of the current user.
Your help will be much appreciated!
Currently my models are like this:
class ParcareManager(models.Manager):
def active(self, *args, **kwargs):
return super(ParcareManager, self).filter(draft=False).filter(parking_on__lte=timezone.now())
class Parcare(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, default=1, on_delete=True)
email=models.EmailField(blank=True, null=True)
# email = models.EmailField(settings.AUTH_USER_MODEL)
parking_on = models.DateField(auto_now=False, auto_now_add=False,blank=True, null=True)
parking_off = models.DateField(
auto_now=False, auto_now_add=False, blank=True, null=True) #plecarea din parcare
location =models.CharField(max_length=120, default="P1", blank=True, null=True)
updated = models.DateTimeField(auto_now=True, auto_now_add=False,blank=True, null=True)
timestamp=models.DateTimeField(auto_now=False, auto_now_add=True,blank=True, null=True)
venire = models.TimeField(default=datetime.time(9, 00),auto_now=False, auto_now_add=False )
plecare = models.TimeField(default=datetime.time(
18, 00), auto_now=False, auto_now_add=False)
objects = ParcareManager()
def __str__(self):
return self.email + " | " + self.location + " | " + str(self.parking_on) + " | " + str(self.parking_off)
class Meta:
verbose_name_plural = "parcare"
class Meta:
ordering = ["-timestamp", "-updated"]
My admin is like this:
from django.contrib import admin
# Register your models here.
from .models import Parcare
class ParcareModelAdmin(admin.ModelAdmin):
list_display = [ "email","user", "location",
"parking_on", "parking_off", "venire", "plecare"]
list_display_links = ["email", "user" ]
list_editable = [ "parking_off", "parking_on","venire", "plecare"]
list_filter = ["parking_on", "parking_off", "venire", "plecare"]
search_fields = ["location", "name"]
class Meta:
model = Parcare
def email(self, obj):
return obj.user.email
admin.site.register(Parcare, ParcareModelAdmin)
If this is the case, then you may try this:
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
if not obj:
user = request.user
form.base_fields['user'].initial = user
form.base_fields['email'].initial = user.email
return form
Here you are fetching the logged in user object from request and then initializing the values from that user.

Order Django admin change list column by output of __unicode()__ method

Here's part of my Django app's models.py:
class Person(models.Model):
birth_year = WideYear(null=True, blank=True)
birth_year_uncertain = models.BooleanField()
death_year = WideYear(null=True, blank=True)
death_year_uncertain = models.BooleanField()
flourit_year = WideYear(null=True, blank=True)
flourit_year_uncertain = models.BooleanField()
FLOURIT_CHOICES = (
(u'D', u'Birth and death dates'),
(u'F', u'Flourit date'),
)
use_flourit = models.CharField('Date(s) to use', max_length=2, choices=FLOURIT_CHOICES)
index_entries = models.ManyToManyField(IndexEntry, null=True, blank=True)
def __unicode__(self):
if self.personname_set.filter(default_name__exact=True):
name = z(self.personname_set.filter(default_name__exact=True)[0])
else:
name = u'[Unnamed person]'
if self.use_flourit == u'D':
dates = '%s - %s' % (z(self.birth_year), z(self.death_year))
else:
dates = 'fl. ' + z(self.flourit_year)
return '%s (%s)' % (name, dates)
class PersonName(models.Model):
titles = models.CharField(max_length=65535, null=True, blank=True)
surname = models.CharField(max_length=255, null=True, blank=True)
first_name = models.CharField(max_length=255, null=True, blank=True)
middle_names = models.CharField(max_length=255, null=True, blank=True)
post_nominals = models.CharField(max_length=65535, null=True, blank=True)
default_name = models.BooleanField()
person = models.ForeignKey(Person, null=True, blank=True)
def __unicode__(self):
return '%s, %s %s' % (self.surname, self.first_name, self.middle_names)
class Meta:
unique_together = ("titles", "surname", "first_name", "middle_names", "post_nominals", "person")
unique_together = ("default_name", "person")
and here are the corresponding parts of my app's admin.py:
from reversion.admin import VersionAdmin
class PersonNameInline(admin.TabularInline):
model = PersonName
extra = 1
class PersonAdmin(VersionAdmin):
radio_fields = {"use_flourit": admin.HORIZONTAL}
inlines = [PersonNameInline]
admin.site.register(Person, PersonAdmin)
In the admin, this produces a change list as follows:
(source: sampablokuper.com)
As you can see, although the change list populates each row of the Person column with the output of the __unicode()__ method of the Person class, it does not order the rows of that column by the __unicode()__ method of the Person class.
How can I make it do so?
Many thanks in advance!
Django ordering is done in the database level. Unless you store the result of your unicode function in the DB, django is not going to be able to natively return results ordered in that fashion.
Storing an ordering value in the DB is probably the most expedient way to solve this problem.
Just hit the same problem, and I found the following link useful. Instead of sorting by unicode, it tries to sort by multiple columns, which may help solve the problem:
http://djangosnippets.org/snippets/2110/
Following Paul McMillan's suggestion, I added the following line to the class definition of Person:
ordering_string = models.CharField(max_length=255, null=True, blank=True)
I also put the this above the PersonName definition in models.py:
def post_save_person_and_person_name(sender, **kwargs):
person_name = kwargs['instance']
person = person_name.person
if person.ordering_string != unicode(person)[0:254]:
person.ordering_string = unicode(person)[0:254]
super(Person, person).save()
and put this below the PersonName definition in models.py:
post_save.connect(post_save_person_and_person_name, sender=PersonName)
So far, so good.
I think I might be able to improve on it by replacing the save() call above with a queryset update() . I'd welcome suggestions on that front!

Resources