Upcoming Contributing to the Django Docs Workshops

2021-06-09 Thread Carlton Gibson
Hi all. 

Daniele Procida will be leading a couple of free workshops on contributing 
to the Django docs, and learning the Diátaxis framework for documentation. 

These will be over the next two Wednesdays, the 16th and 23rd of June, at 
different times to be available as many timezones as possible. 

There’s a sign-up form, with more information here: 

https://docs.google.com/forms/d/1WC0mXNEf7kwDaS_3Q1d5WeQz5dJM8A1fWvna-_UrkNw 


Do check it out. It’s a wonderful offer and opportunity.  Daniele has been 
a long time member of the Django community (do search for his DjangoCon 
talks if you don’t know him) and, after several years at Divio, is off to 
lead the documentation efforts at Canonical. To have him share his 
knowledge with us is a real treat.

Kind regards, Carlton 

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/9396f0f3-ba31-4432-89df-f42afea395c9n%40googlegroups.com.


Re: `Model.validate_unique` excluding partial unique constraint

2021-06-09 Thread charettes
Alright so here's for a few hints about I believe things should be done.

First things first Lookup must be made a subclass of Expression which is 
being worked on[0].

Ideally Q would also be made a subclass of Expression but that's likely a 
big can of worms so I'd focus on implementing it for Q only at first.

Now for the compiler part. Things are bit tricky here as these expressions 
are not going to be bound to a model/table and most of the sql.Query and 
resolve_expression machinery revolves around the availability of a 
Query.model: models.Model property. I think there's two solutions here:

1. Adapt sql.Query so it can be *unbounded* meaning that it's .model 
property type would change from models.Model to Optional[models.Model]. 
2. Follow the sql.RawQuery route and define a new sql.UnboundQuery class 
that *looks* like a Query but doesn't allow any form of column references 
or JOINs or filters (WHERE).

In both cases the Query like object should prevent any form of column 
references and JOINs with a comprehensible error messages (e.g. in resolve_ref 
and setup_join if go with 1.). I have a feeling 2. is easier to implement 
but 1. seems like it could be a much more rewarding experience for you and 
the community as you'll have to special case a couple of long lived 
assumptions in django.db.models.sql.

Depending on whether you choose the 1. or 2. you'll have to implement a way 
for database backends to specify how to *wrap* the provided expression in a 
SELECT statement. Most databases won't require any special casing but I 
know that Oracle will require the addition of a trailing "DUAL" clause 
(SELECT ... FROM DUAL)[1] and possibly some special casing of expressions 
such as exists but there's already pre-existing logic for that[2]. If you 
go with 1. this can be done by returning a backend specific string in 
SQLCompiler.get_from_clause when self.query.alias_map is empty[3].

In the end the call stack should be (assuming 1. is followed):

Q.check(self, using):
  query = Query()
  query.add_annotations(self, '_check')
  query.set_values('_check')
  compiler = query.get_compiler(using=db)
  result = compiler.execute_sql(SINGLE)
  return bool(result[0])

I hope this clears things up a bit!

Cheers,
Simon

[0] https://github.com/django/django/pull/14494
[1] https://docs.oracle.com/cd/B19306_01/server.102/b14200/queries009.htm
[2] 
https://github.com/django/django/blob/ed3af3ff4b3cfb72de598f1b39a1028ba3826efb/django/db/models/expressions.py#L382-L389
[3] 
https://github.com/django/django/blob/ed3af3ff4b3cfb72de598f1b39a1028ba3826efb/django/db/models/sql/compiler.py#L797-L810

Le mercredi 2 juin 2021 à 11:36:02 UTC-4, gaga...@gmail.com a écrit :

> Thanks for the thorough answer. I also realize now that it worked in my 
> app only because of another side effect when my instance was saved..
>
> I started to take a look at the ORM part where the check method should be 
> implemented as I'm not used to it. Shouldn't .check() be implemented on Q 
> and not on Expression? Or are you including Lookup / Q in it?
>
> Then I'd guess it's just a matter of calling as_sql() from each part and 
> assemble them. Everythings we need seems to be done in Query and we can't 
> use it as it has to be linked to a model, so we would have to redo it? 
> Although as_sql needs a compiler which itself needs a query. I admit I'm a 
> bit lost in all those classes, everything seems to be too much linked to 
> the models to do something without one.
>
> If you have any more hints as to where I should look, thanks again.
> Le mercredi 2 juin 2021 à 00:33:12 UTC+2, charettes a écrit :
>
>> Hello there,
>>
>> Partial unique constraints are currently not supported during validation 
>> for reasons described in this ticket[0].
>>
>> For example (inspired by this Github comment[1]), if you define the 
>> following model
>>
>> class Article(models.Model):
>> slug = models.CharField(max_length=100)
>> deleted_at = models.DateTimeField(null=True)
>>
>> class Meta:
>> constraints = [
>> UniqueConstraint('slug', condition=Q(deleted_at=None), 
>> name='unique_slug'),
>> ]
>>
>> Then validate_unique must perform the following query to determine if the 
>> constraint is violated
>>
>> SELECT NOT (%(deleted_at)s IS NULL) OR NOT EXISTS(SELECT 1 FROM article 
>> WHERE NOT id = %(id)s AND slug = %(slug)s AND deleted_at IS NULL)
>>
>> In other words, the validation of a partial unique constraint must check 
>> that either of these conditions are true
>> 1. The provided instance doesn't match the condition
>> 2. There's no existing rows matching the unique constraint (excluding the 
>> current instance if it already exists)
>>
>> This is not something Django supports right now.
>>
>> In order to add proper support for this feature I believe (personal 
>> opinion here feedback is welcome) we should follow these steps:
>>
>> 1. Add support for Expression.check(using: str) -> bool that would 
>> translate I